上一篇中,我们已经介绍了互斥锁,实现了对临界资源的保护,并且我们留下了一个悬念:
解决了临界资源的访问,但似乎对线程的执行顺序无法得到控制,因线程 都是无序执行,之前采用sleep强行延时的方法勉强可以控制执行顺序,但此 方法在实际项目情况往往是不可取的,其仅仅可解决线程创建的顺序,当创建之后执行的顺序又不会受到控制,于是便引入了信号量的概念,解决线程执行顺序。
所以,接下来,我们来讲讲多线程编执行顺序控制:
信号量API简述
函数原型如下:
⚫ 该函数可以初始化一个信号量,第一个参数传入sem_t类型指针;
⚫ 第二个参数传入0代表线程控制,否则为进程控制;
⚫ 第三个参数表示信号量的初始值,0代表阻塞,1代表运行。
⚫ 待初始化结束信号量后,若执行成功会返回0。
信号量P/V操作
函数原型如下:
⚫ sem_wait函数作用为检测指定信号量是否有资源可用,若无资源可用会阻塞 等待,若有资源可用会自动的执行“sem-1”的操作。所谓的“sem-1”是与上述 初始化函数中第三个参数值一致,成功执行会返回0。
⚫ sem_post函数会释放指定信号量的资源,执行“sem+1”操作。
通过以上2个函数可以完成所谓的PV操作,即信号量的申请与释放,完成 对线程执行顺序的控制。
信号量申请(非阻塞方式)
函数原型如下:
此函数是信号量申请资源的非阻塞函数,功能与sem_wait一致,唯一区别在于此函数为非阻塞。
信号量销毁
函数原型如下:
该函数为信号量销毁函数,执行过后可将信号量进行销毁。
测试例程12:(Phtread_txex12.c)
运行结果:
该例程加入了信号量,使得线程的执行顺序变为可控的。在初始化信号量时, 将信号量1填入资源,第一个线程调用sem_wait函数可以成功获得信号量,在 执行完逻辑后使用sem_pos函数来释放。当执行函数sem_wait后,会执行sem 自减操作,使下一次竞争被阻塞,直至通过sem_pos被释放。
上述例程因38行初始化信号量1时候,使其默认获取到资源;第 43、48行 初始化信号量2、3时候,使之没有资源。于是在线程处理函数中,每个线程通 过sem_wait函数来等待资源,发生阻塞。因信号量1初始值为有资源,故可以 先执行线程1的逻辑。待执行完第12行sem_wait函数,会导致sem1-1,使得 下一次此线程会被阻塞。继而执行至14行,通过sem_post函数使sem2信号量 获取资源,从而冲破阻塞执行线程2的逻辑...以此类推完成线程的有序控制。
下面再来讲一个东西,其实小编之前也没有接触过这个:
条件变量:
条件变量时一种同步机制,用来通知其他线程条件满足了。一般是用来通知 对方共享数据的状态信息,因此条件变量时结合互斥量来使用的。(看到这个突然就想起来了,好像之前接触过(doge.))
创建和销毁条件变量
函数原型如下:
等待条件变量
函数原型如下:
这需要结合互斥量一起使用,示例代码如下:
通知条件变量
函数原型如下:
pthread_cond_signal 函数只会唤醒一个等待cond条件变量的线程,示 例代码如下:
这个大概讲一下就行了,感觉用处也不是很大,后面要用到再来细细探讨吧(doge.)
那关于多线程的,就差不多讲完了,下面我们来总结一下吧
总结:
线程使用流程图:
有关多线程的创建流程如图 9.14所示,首先需要创建线程,一旦线程创 建完成后,线程与线程之间会发生竞争执行,抢占时间片来执行线程逻辑。在 创建线程时候,可以通过创建线程的第四个参数传入参数,在线程退出时亦可 传出参数被线程回收函数所回收,获取到传出的参数。
互斥量使用流程图:
当多个线程出现后,会遇到同时操作临界公共资源的问题,当线程操作公 共资源时需要对线程进行保护加锁,防止其与线程在此线程更改变量时同时更 改变量,待逻辑执行完毕后再次解锁,使其余线程再度开始竞争。互斥锁创建 流程下图所示。
信号量使用流程图:
当多个线程出现后,同时会遇到无序执行的问题。有时候需要对线程的执 行顺序做出限定,变引入了信号量,通过PV操作来控制线程的执行顺序,如下 图所示。
那么到这里,我们就全部讲完啦,完结,撒花(doge.)