十年老司机详解Linux多线程技术下篇(含实例源码,值得收藏)

线程同步

条件变量

条件变量就是一个变量,用于线程等待某件事情的发生,当等待事件发生时,被等待的线程和事件一起继续执行。等待的线程处于睡眠状态,直到另一个线程将它唤醒,才开始活动,条件变量用于唤醒线程。

互斥锁一个明显的缺点就是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。

操作函数

pthread_cond_t是条件变量类型,用于定义条件变量。

条件变量初始化函数int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr);

函数说明:cond参数为条件变量指针,通过该函数实现条件变量赋初值;attr参数通常为NULL。

线程同步等待函数(睡眠函数)int pthread_cond_wait(pthread_cond_t & restrict cond, pthread_mutex_t * restrict mutex);

函数说明:cond参数为条件变量,mutex参数为互斥量。

说明:哪一个线程执行pthread_cond_wait,哪一个线程就开始睡眠,在睡眠时同时先解开互斥锁,以便让其他线程可以继续执行。

发送条件信号(唤醒函数)int pthread_cond_signal(pthread_cond_t * cond);

函数说明:cond参数为条件变量。

说明:在另一个线程中使用,当某线程符合某种条件时,用于唤醒其他线程,让其他线程同步运行。其他线程被唤醒后,马上开始加锁,如果此时锁处于锁定状态,则等待被解锁后向下执行销毁。

条件变量销毁int pthread_cond_destory(pthread_cond_t * cond);

函数说明:cond参数为条件变量。

例子:

十年老司机详解Linux多线程技术下篇(含实例源码,值得收藏)

这里讲一下:互斥量与条件变量为什么要配合使用?

条件变量用在某个线程需要在某种条件才会进行某些操作的情况下,从而避免了线程不断轮询检查该条件是否成立而降低效率的情况,这是实现了效率提高。

条件变量这个变量其实本身不包含条件信息,条件的判断不在pthread_cond_wait函数功能中,而需要外面进行条件判断。这个条件通常是多个线程或进程的共享变量,这样就很清楚了,对于共享变量很可能产生竞争条件尤其还对共享变量加了条件限制,所以从这个角度看,必须对共享变量加上互斥锁。

加上互斥锁,就会出现因为要不断地判断条件是否成立而不断地开锁、解锁的过程。比如,线程2的任务是输出“Hello World”,但是必须满足条件iCount等于100。由于iCount是线程共享变量,所以必须使用互斥锁:

十年老司机详解Linux多线程技术下篇(含实例源码,值得收藏)

这是很复杂的,线程2需要不断地开锁、检查、解锁,浪费了很多的系统资源。这个时候就有一个办法了,让线程2堵塞休眠,当线程1达到条件的时候直接通知线程2,把它唤醒,这样就避免浪费了。

同时还要注意一个过程:

pthread_cond_wait():这个函数的过程我们必须了解,首先对互斥锁进行解锁;然后自身堵塞等待;当等待条件达成,注意这时候函数并未返回,而是重新获得锁并返回。

所以:pthread_cond_wait()本身提供的重要功能是,保证这些操作一定是原子操作不可分割。

试想一下,如果进程A调用了pthread_cond_wait(),先进行了解锁,这时候由于进程A时间片到期,轮换到进程B,进程B一直想要这把锁,现在终于拿到了,它干完了事情,调用pthread_cond_signal()想唤醒A但是A并未完成睡眠等待条件达成,所以这个唤醒信号就丢失了。信号量

信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问,也被称为PV原子操作。

PV原子操作,广泛用于进程或线程之间的通信的同步和互斥。其中,P是通过的意思,V是释放的意思,不可中断的过程,则由操作系统来保证P操作和V操作。PV操作时针对信号量的操作,就是对信号量进行加减的过程。

P操作,即信号量sem减一的过程,如果sem小于等于0,P操作被堵塞,直到sem变量大于0为止。P操作即加锁过程。

V操作,即信号量sem加一的过程。V操作即解锁过程。

操作函数

信号量初始化int sem_init(sem_t *sem, int pshared, unsigned int value);

函数说明:sem参数是信号量指针;pshared参数为共享方式,0表示信号量只是在当前进程中使用(线程),1表示信号量在多进程中使用;value参数表示信号量的初始值,一般为1。

P操作,减少信号量int sem_wait(sem_t *sem);

V操作,增加信号量int sem_post(sem_t *sem);

销毁信号量int sem_destory(sem_t *sem);

获取信号量的值int sem_getvalue(sem_t *sem, int *sval);

十年老司机详解Linux多线程技术下篇(含实例源码,值得收藏)

需要C/C++ Linux服务器开发学习资料私信“资料”(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

编程资源库微信号:暂无扫描二维码关注公众号
爱八卦,爱爆料。

小编推荐

  1. 1 如何把两个pdf文件合成一个(怎么样把两个pdf文件合成一个)

    大家好,小伟今天来为大家解答如何把两个pdf文件合成一个以下问题,怎么样把两个pdf文件合成一个很多人还不知道,现在让我们一起来看看吧!1、

  2. 2 中药降血糖最好的方法(中药降血糖)

    大家好,小丽今天来为大家解答中药降血糖最好的方法以下问题,中药降血糖很多人还不知道,现在让我们一起来看看吧!1、生黄芪配生地降尿糖,

  3. 3 无氧运动(无氧运动能减肥吗)

    大家好,小豪今天来为大家解答无氧运动以下问题,无氧运动能减肥吗很多人还不知道,现在让我们一起来看看吧!1、“无氧运动”的英文是“Ana

  4. 4 日语再见sayonara(日语再见发音在线听)

    大家好,小伟今天来为大家解答日语再见sayonara以下问题,日语再见发音在线听很多人还不知道,现在让我们一起来看看吧!1、对了,就是英文音译

  5. 5 李海欣个人简介(李海欣烈士生前的最后一张照片)

    大家好,小伟今天来为大家解答李海欣个人简介以下问题,李海欣烈士生前的最后一张照片很多人还不知道,现在让我们一起来看看吧!1、1984年5月

  6. 6 五号字体是多大尺寸(五号字体有多大)

    大家好,小美今天来为大家解答五号字体是多大尺寸以下问题,五号字体有多大很多人还不知道,现在让我们一起来看看吧!1、一般word中默认的字体

  7. 7 莱卡是什么面料(弹力莱卡是什么面料)

    大家好,小娟今天来为大家解答莱卡是什么面料以下问题,弹力莱卡是什么面料很多人还不知道,现在让我们一起来看看吧!1、您好!莱卡面料是由

  8. 8 承前启后继往开来的意思(承前启后继往开来对联)

    大家好,小伟今天来为大家解答承前启后继往开来的意思以下问题,承前启后继往开来对联很多人还不知道,现在让我们一起来看看吧!1、“承前启

Copyright 2024 看看网,让大家及时掌握各行各业第一手资讯新闻!