购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.7 线程同步:信号量

本节详细讲解另一种POSIX线程信号量,它允许进程和线程同步对共享资源进行访问。POSIX信号量分为两种: 命名信号量 未命名信号量 。命名信号量是全局命名的信号量,主要用在进程间通信上,不同的进程可以通过名字来访问同一个信号量,可通过sem_open函数来创建。未命名信号量是指没有名字的信号量,它存在于内存中预定的位置(全局变量、静态变量等),未命名信号量主要在线程间共享。

1.7.1 初始化未命名信号量

sem_init函数可对未命名信号量进行初始化,sem是未命名信号的对象,value是默认初始化值,其定义如下所示。

pshared参数表示这个信号量的共享范围,0表示是在线程间共享,不等于0表示在进程间共享。在线程间共享时,sem通常被指定为一个全局变量的地址或分配在堆内存上的一个变量地址。线程共享的信号量是依托进程而存在的,主进程终止时信号量会被一同销毁。

1.7.2 等待一个信号量

sem_wait函数会将sem引用的信号量的值减去1。如果信号量的当前值大于0,那么sem_wait函数会减1并立即返回。如果信号量的当前值等于0,则sem_wait函数会将当前的线程阻塞,即当前线程会被挂起。当信号量值再次大于0时,会将处于等待状态的线程唤醒,并将信号量值减1。sem_wait函数的定义如下。

1.7.3 发布一个信号量

sem_post函数会把sem引用的信号量的值加1,函数定义如下所示。当有一个线程阻塞在这个信号量上时,sem_post函数会把处于阻塞状态的线程唤醒。

如果多个线程都阻塞在当前信号量上,则具体唤醒哪个线程由调度策略决定。

代码清单1-21是一个关于信号量使用的简单例子,首先定义了全局信号量countSem,用来进行并发线程的控制。然后定义了数据自增的函数increment,执行自增之前要获取countSem信号量,自增结束之后释放countSem信号量。

代码清单1-21 信号量示例

在main函数中对信号量countSem进行初始化,将其设置成线程间共享,且初始化的值为2。接着定义了3个线程来执行任务,每个线程在执行具体任务前都需要获取countSem信号量。这样我们就能通过countSem信号量来实现线程同步了,如在任何一个时刻只有两个线程能同时执行。

POSIX信号量和互斥量都可以用来完成线程间的同步操作,并且两者的性能也是相近的。通常互斥量是首选方法,因为互斥量具有排他性,能够更好地进行并发控制。但如果只允许有限的线程来访问同一个资源,POSIX信号量则非常合适。例如在上面的例子中,我们就可以通过信号量来控制,因为在任何时候只有两个线程能同时执行。 ipEVnri3LsckHk7p9DFnjWNKYMhheXoGktWqlQN4yCoqt/b/EV/T5oZMZ4AZNEkK

点击中间区域
呼出菜单
上一章
目录
下一章
×