一、信号量和条件变量的异同
- 信号量和条件变量都可以允许多个线程以无竞争的方式等待特定条件或信号的产生;
- 信号量在使用时会设置一个初始值,每次只能唤醒一个正在等待信号的线程,而条件变量则没有初始值,并且可以一次性唤醒所有等待条件变量的线程;
- 条件变量一般和互斥锁一起使用,这一点比信号量稍微麻烦一些;
二、信号量使用注意事项
- 如果信号量的初始值不为0,那么即使不调用sem_post,使用sem_wait的线程依然可以被唤醒,直到信号量的值为0;
- 每一次调用sem_post,信号量的值都会被加一,每一次调用sem_wait解除线程的阻塞,信号量的值都会被减一。
二、常用函数
头文件:#include <semaphore.h>
1.sem_init
函数原型:int sem_init(sem_t *sem, int pshared, unsigned int value);
函数功能:初始化一个信号量,并设置信号量的初始值为value,每次调用sem_post信号量的值会加一
函数参数:sem 信号量句柄
shared 0表示信号量只能在线程间使用,非0值表示可以在进程间使用
value 初始值
返回值:成功返回0,失败返回对应的错误码
2.sem_post
函数原型:int sem_post(sem_t *sem);
函数功能:调用该函数可以唤醒使用sem_wait函数等待信号量的线程,同时sem指向的信号值会加一。
函数参数:sem 信号量句柄
返回值:成功返回0,失败返回对应的错误码
3.sem_wait
函数原型:int sem_wait(sem_t *sem);
函数功能:阻塞等待信号量的到来,同时sem指向的信号值会减一。
4.sem_trywait
函数原型:int sem_wait(sem_t *sem);
函数功能:非阻塞等待信号量的到来,如果信号量的值为0,返回对应的错误码
5.sem_timedwait
函数原型: int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
函数功能:阻塞等待信号量的到来,并设置超时时间
6.sem_timedwait
函数原型: int sem_getvalue(sem_t *sem);
函数功能:获取信号量的当前值
7.sem_destroy
函数原型: int sem_destroy(sem_t *sem);
函数功能:销毁信号量
8.sem_getvalue
函数原型: int sem_getvalue(sem_t *sem, int *sval);
函数功能:获取信号量的当前值
示例:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t g_sem;
void *pthread1(void *param)
{
int value;
while(1)
{
sem_post(&g_sem);
sem_getvalue(&g_sem,&value);
printf("sem post,signal num:%d\r\n",value);
sleep(1);
}
}
void *pthread2(void *param)
{
int ret = -1;
int value;
while(1)
{
ret = sem_wait(&g_sem);
if(0 == ret)
{
sem_getvalue(&g_sem,&value);
printf("sem wait,signal num:%d\r\n",value);
}
}
}
int main()
{
int ret = -1;
pthread_t tid1,tid2;
ret = sem_init(&g_sem,0,5);
if(0!=ret)
{
printf("sem init error\r\n");
}
pthread_create(&tid1,NULL,pthread1,NULL);
pthread_create(&tid2,NULL,pthread2,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X9C32f9F-1595729944368)(2F6352567AA34A3A8AE019D1ADDD67FF)]
如果长时间运行会出现num都为0的情况,这是因为sem_post之后,获取到的value值已经被sem_wait修改。