互斥量相当与锁,在使用共享资源时,对它加锁,使用完后,释放锁,在加锁期间,其他的线程不能对该共享资源进行操作.
数据类型:pthread_mutex_t
相关API
初始化和销毁互斥量
初始化一个互斥量时也可以赋值为PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutext_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//attr设置为NULL,代表以默认属性初始化互斥量
int pthread_mutex_destroy(pthread_mutex_t *mutex);
加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
//对互斥量加锁,若互斥量已加锁,则会阻塞,直到信号量解锁,成功返回0,
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//如果信号量没被锁,则加锁,并返回0,若信号已被锁,则不会阻塞,返回一个非0值
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict tsptr);
//当线程试图获取一个已经加锁的互斥量时,该函数可以设置等待时间,若在该时间内,互斥量被解锁,则调用该函数的线程可以继续运行,若没有解锁,则该函数不会对互斥量加锁,而是返回一个错误代码ETIMEDOUT,成功返回0
#include <stdlib.h>
#include <unistd.h>
struct foo
{
int f_count;
pthread_mutex_t f_lock;
int f_id;
};
struct foo* foo_alloc(int id)
{
struct foo * fp;
if((fp=malloc(sizeof(struct foo))!=NULL)
{
fp->f_count=1;
fp->f_id=id;
if(pthread_mutex_init(&fp->f_lock,NULL)!=0)
{
free(fp);
return (NULL);
}
}
return (fp);
}
void foo_hold(struct foo * fp)
{
pthread_mutex_lock(&fp->f_lock);
fp->f_count++;
pthread_mutex_unlock(&fp->f_lock);
}
void foo_rele(struct foo *fp)
{
pthread_mutex_lock(&fp->f_lock);
if(--fp->f_count==0)
{
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_destroy(&fp->f_lock);
free(fp);
}
else
{
pthread_mutex_unlock(&fp->f_lock);
}
}
读写锁
读写锁有三种状态,加读锁,加写锁,不加锁,当位于写锁时,所有企图对读写锁加锁(无论时加读锁还是写锁)的线程都会阻塞,当位于加读锁时,所有试图对其加读锁的线程可以继续运行,但是加写锁的线程会阻塞。当读写锁位于读状态时,如果有一线程试图对其加写锁,那么读写锁通常会阻塞随后的加读锁请求,这样可以避免读模式锁长期占用,而写模式锁请求得不到满足。
数据类型 pthread_rwlock_t
#include <pthread.h>
int pthread_rwclock_init(pthread_rwlock_t *restrict rwlock,const pthread_relockattr_t *restrict attr); //初始化一个读写锁,要先分配内存。
int pthread_rwclock_destroy(pthread_rwlock_t *rwlock) //销毁锁 。2个函数成功返回0
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); //加读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); //加写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); //解锁 若成功都返回0
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); //成功返回0
条件变量
如果说互斥锁用于同步线程对共享数据的访问,那么条件变量就是用于同步共享数据的值。
#include <pthread.h>
int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t* cond_attr);
初始化一个条件量,若cond_attr为NULL,则以默认熟悉初始化,还可以pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
int pthread_cond_destroy(pthread_cond_t* cond);
int pthread_cond_signal(pthread_cond_t* cond);
唤醒一个等待该条件变量的线程
int pthread_cond_broadcast(pthread_cond_t* cond);
唤醒所有等待该条件变量的线程
int pthread_cond_wait(pthread_cond_t* cond,pthread_mutex_t* mutex);
等待目标条件变量,mutex用来保证该函数操作的原子性,在使用pthread_cond_wait函数之前,需保证对mutex加锁。该函数执行时,把调用线程加入条件变量的等待队列。调用完后需要对mutex解锁。
上面的函数成功返回0,失败返回错误代码。
下面是一个线程同步机制的包装类
#include <exception>
#include <pthread.h>
#include <semphore.h>
class sem{
public:
sem(unsigned int val=0){
if(sem_init(&m_sem,0,val)!=0){
throw std::exception(); //constructor don't have return val,if error,throw a exception
}
}
~sem(){
sem_destroy(&m_sem);
}
//equal p operation
bool wait(){
return sem_wait(&m_sem)==0;
}
//equal v operation
bool post(){
return sem_post(&m_sem)==0;
}
private:
sem_t m_sem;
};
class locker{
public:
locker(){
if(pthread_mutex_init(&m_mutex,NULL)!=0){
throw std::exception();
}
}
~locker(){
pthread_mutex_destroy(&m_mutex);
}
bool lock(){
return pthread_mutex_lock(&m_mutex)==0;
}
bool unlock(){
return pthread_mutex_unlock(&m_mutex)==0;
}
private:
pthread_mutex_t m_mutex;
};
class cond{
public:
cond(){
if(pthread_mutex_init(&m_mutex,NULL)!=0){
throw std::exception();
}
if(pthread_cond_init(&m_cond,NULL)!=0){
pthread_mutex_destroy(&m_mutex);
throw std::exception();
}
}
~cond(){
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
bool wait(){
int ret=0;
pthread_mutex_lock(&m_mutex);
ret=pthread_cond_wait(&m_cond,&m_mutex);
pthread_mutex_unlock(&m_mutex);
return ret==0;
}
bool signal(){
return pthread_cond_signal(&m_cond)==0;
}
private:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};