线程的最大特点是资源的共享性,linux下提供了多种方式来处理线程同步,最常用的是互斥锁、条件变量、信号量、读写锁。
1)互斥锁(mutex)
通过锁机制实现线程间的同步。同一时刻只允许一个线程执行一个关键部分的代码。
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex *mutex);
int pthread_mutex_destroy(pthread_mutex *mutex);
int pthread_mutex_unlock(pthread_mutex *);
(1)先初始化锁init()或静态赋值pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIER
init()函数的参数二有以下四种类型:
PTHREAD_MUTEX_TIMED_NP:其余线程等待队列
PTHREAD_MUTEX_RECURSIVE_NP:嵌套锁,允许线程多次加锁,不同线程,解锁后重新竞争
PTHREAD_MUTEX_ERRORCHECK_NP:检错,与一同,线程请求已用锁,返回EDEADLK;
PTHREAD_MUTEX_ADAPTIVE_NP:适应锁,解锁后重新竞争
(2)加锁,lock,trylock,lock阻塞等待锁,trylock立即返回EBUSY
(3)解锁,unlock需满足是加锁状态,且由加锁线程解锁
(4)清除锁,destroy(此时锁必需unlock,否则返回EBUSY,//Linux下互斥锁不占用内存资源
2)条件变量(cond)
利用线程间共享的全局变量进行同步的一种机制。条件变量上的基本操作有:触发条件(当条件变为 true 时);等待条件,挂起线程直到其他线程触发条件。
常用函数如下:
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞
- 使用流程如下:
(1)初始化.init()或者pthread_cond_t cond=PTHREAD_COND_INITIALIER(前者为动态初始化,后者为静态初始化);属性置为NULL
(2)等待条件成立.pthread_wait,pthread_timewait.wait()释放锁,并阻塞等待条件变量为真,timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait)
(3)**条件变量:pthread_cond_signal,pthread_cond_broadcast(**所有等待线程)
(4)清除条件变量:destroy;无线程等待,否则返回EBUSY
- 说明:
1、pthread_cond_wait、pthread_cond_timewait 的互斥锁区域内使用
2、pthread_cond_wait 自动解锁互斥量(如同执行了pthread_unlock_mutex),并等待条件变量触发。这时线程挂起,不占用CPU时间,直到条件变量被触发(变量为ture)。在调用 pthread_cond_wait之前,应用程序必须加锁互斥量。pthread_cond_wait函数返回前,自动重新对互斥量加锁(如同执行了pthread_lock_mutex)。
3、pthread_cond_destroy 销毁一个条件变量,释放它拥有的资源。进入 pthread_cond_destroy 之前,必须没有在该条件变量上等待的线程。
4、条件变量函数不是异步信号安全的,不应当在信号处理程序中进行调用。特别要注意,如果在信号处理程序中调用 pthread_cond_signal 或pthread_cond_boardcast 函数,可能导致调用线程死锁。
3)线程信号量(无名信号量)
无名信号量不能用进程间通信,用于线程间通信;有名信号量可用于进程和线程,但一般用于进程。
线程信号量(无名信号量)头文件:semaphore.h;
进程信号量(有名信号量)头文件:sys/sem.h。
线程使用的信号量基本函数有四个:
1、int sem_init (sem_t *sem , int pshared, unsigned int value);
对由sem指定的信号量进行初始化,设置好它的共享选项(linux中,sem_init的第二个参数必须为0,表示线程间通信),然后给它一个初始值VALUE。
2、int sem_wait(sem_t *sem);
原子操作函数,给信号量的值加1,相当于V操作;
3、int sem_post(sem_t *sem);
原子操作函数,给信号量减1,相当于P操作;对一个值为0的信号量调用sem_wait,这个函数将会等待直到有其它线程使它不再是0为止。
4、int sem_destroy(sem_t *sem);
这个函数的作用是再我们用完信号量后进行清理。归还自己占有的一切资源。
4)读写锁
读写基本原则:
- 若当前线程读数据,则允许其他线程读数据,但不允许写
- 若当前线程写数据,则不允许其他线程读、写数据
参考链接:https://www.cnblogs.com/Jimmy1988/p/7822478.html