超详细讲解Linux|超详细讲解Linux C++多线程同步的方式

目录

  • 一.互斥锁
    • 1.互斥锁的初始化
    • 2.互斥锁的相关属性及分类
    • 3.测试加锁函数
  • 二.条件变量
    • 1.条件变量的相关函数
  • 三.读写锁
    • 1)初始化的销毁读写锁
    • 2)以写的方式获取锁,以读的方式获取锁,释放读写锁
  • 四.信号量
    • 1)信号量初始化
    • 2)信号量值的加减
    • 3)对信号量进行清理
背景问题:在特定的应用场景下,多线程不进行同步会造成什么问题?
通过多线程模拟多窗口售票为例:
#include #include#include#include#include#includeusing namespace std; int ticket_sum=20; void *sell_ticket(void *arg){for(int i=0; i<20; i++){if(ticket_sum>0){sleep(1); cout<<"sell the "<<20-ticket_sum+1<<"th"<0){sleep(1); cout<<"thread_2 sell the "<<20-ticket_sum+1<<"th tickets"<
分析:线程1不满足条件被阻塞,然后线程2运行,改变了条件,线程2发行条件改变了通知线程1运行,然后线程2结束,然后线程1继续运行,然后线程1结束,为了确保线程1先执行,在创建线程2之前我们sleep了2秒
ps:
1.条件变量通过运行线程阻塞和等待另一个线程发送信号的方法弥补互斥锁的不足,常常和互斥锁一起使用,使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开响应的互斥锁并等待条件发生变化,一旦其他的某个线程改变了条件变量,它将通知响应的条件变量换线一个或多个正被此条件变量阻塞的线程,这些线程将重新锁定互斥锁并且重新测试条件是否满足

1.条件变量的相关函数
1)创建
静态方式:pthread_cond_t cond PTHREAD_COND_INITIALIZER
动态方式:int pthread_cond_init(&cond,NULL)
Linux thread 实现的条件变量不支持属性,所以NULL(cond_attr参数)
2)注销
int pthread_cond_destory(&cond)
只有没有线程在该条件变量上,该条件变量才能注销,否则返回EBUSY
因为Linux实现的条件变量没有分配什么资源,所以注销动作只包括检查是否有等待线程!(请参考条件变量的底层实现)
3)等待
条件等待:int pthread_cond_wait(&cond,&mutex)
计时等待:int pthread_cond_timewait(&cond,&mutex,time)
1.其中计时等待如果在给定时刻前条件没有被满足,则返回ETIMEOUT,结束等待
2.无论那种等待方式,都必须有一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait形成竞争条件!
3.在调用pthread_cond_wait前必须由本线程加锁
4)激发
激发一个等待线程:pthread_cond_signal(&cond)
激发所有等待线程:pthread_cond_broadcast(&cond)
重要的是,pthread_cond_signal不会存在惊群效应,也就是是它最多给一个等待线程发信号,不会给所有线程发信号唤醒提他们,然后要求他们自己去争抢资源!
pthread_cond_signal会根据等待线程的优先级和等待时间来确定激发哪一个等待线程
下面看一个程序,找到程序存在的问题
#include #include#include#include#include#include#includeusing namespace std; pthread_cond_t taxi_cond=PTHREAD_COND_INITIALIZER; //taix arrive condpthread_mutex_t taxi_mutex=PTHREAD_MUTEX_INITIALIZER; // sync mutexvoid *traveler_arrive(void *name){cout<<"Traveler:"<<(char*)name<<" needs a taxi now!"<
分析:3个读线程,2个写线程,读线程比写线程多
当读写锁是写状态时,在锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞
当读写锁是读状态时,在锁被解锁之前,所有视图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行加锁的线程会被阻塞
所以读写锁默认是强读模式!

四.信号量 信号量(sem)和互斥锁的区别:互斥锁只允许一个线程进入临界区,而信号量允许多个线程进入临界区

1)信号量初始化
int sem_init(&sem,pshared,v)
pshared为0表示这个信号量是当前进程的局部信号量
pshared为1表示这个信号量可以在多个进程之间共享
v为信号量的初始值
成功返回0,失败返回-1

2)信号量值的加减
int sem_wait(&sem):以原子操作的方式将信号量的值减去1
int sem_post(&sem):以原子操作的方式将信号量的值加上1

3)对信号量进行清理
int sem_destory(&sem)
通过信号量模拟2个窗口,10个客人进行服务的过程
样例:
#include #include#include#include#include#include#include#includeusing namespace std; int num=10; sem_t sem; void *get_service(void *cid){int id=*((int*)cid); if(sem_wait(&sem)==0){sleep(5); cout<<"customer "<
分析:信号量的值代表空闲的服务窗口,每个窗口一次只能服务一个人,有空闲窗口,开始服务前,信号量-1,服务完成后信号量+1
总结完毕:Linux c++线程同步的四种方式:互斥锁,条件变量,读写锁,信号量
【超详细讲解Linux|超详细讲解Linux C++多线程同步的方式】到此这篇关于超详细讲解Linux C++多线程同步的方式的文章就介绍到这了,更多相关Linux C++多线程同步内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    推荐阅读