互斥量相当与锁,在使用共享资源时,对它加锁,使用完后,释放锁,在加锁期间,其他的线程不能对该共享资源进行操作.
数据类型: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; };