一、信号量是什么?
为什么需要用信号量?在POSIX线程库(二)线程同步轮询技术——一种笨笨方法 简单的变量+延迟的方法是一种非常不聪明的方法,主要原因是普通变量不能保证原子性,同时对标志的操作可能导致预料外的效果。荷兰科学家Dijkstra提出信号量的概念,它是一种特殊的变量,可以被递增递减,当两个或以上线程对这个信号量进行改变,由系统按顺序完成线程的请求。信号量常用来保护一段代码,保证一次只能被一个线程执行。
二、信号量API
使用一个信号量,其基本步骤是:
- 声明一个信号量
- 初始化一个信号量
- 线程1使用sem_post增加信号量
- 线程2中调用sem_wait条件阻塞完成信号同步
- 销毁信号量
头文件#include <semaphore.h>
声明
sem_t bin_sem;
初始化
int sem_init(sem_t *sem,int pshared,unsigned int value);
sem_t * sem
声明的信号量地址int pshared
一般将其设置为0,表示这是一个局部信号量(单进程共享),迄今为止,Linux尚未支持多个进程共享(传递会失败)。unsigned int value
信号量初值- 返回值,0表示相安无事,反之创建失败
增加、减少信号量
int sem_post(sem_t * sem);
int sem_wait(sem_t * sem);
sem_wait
和sem_post
都接受一个信号量地址,和初始化一样,成功0,失败!0。值得注意的是,sem_wait
可能阻塞当前进程,阻塞的条件是,递减后为负数,也就是信号量为0,要想继续执行,需要调用sem_post
完成信号量递增。
销毁
int sem_destory(sem_t * sem);
好吧!和所有信号量相关的API都需要传入信号量地址。当一些线程正在等待状态,返回非0,成功销毁则返回0。
三、Demo time!!!
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t t;
using namespace std;
void *thfun1(void *)
{
sem_post(&t);
for(int i=0;i<10;i++)
{
sem_wait(&t);
cout<<"a";
}
}
void* thfun2(void *)
{
for(int i=0;i<10;i++)
{
cout<<"b";
sem_post(&t);
usleep(1);
}
}
using namespace std;
int main()
{
pthread_t th1,th2;
sem_init(&t,0,0);
pthread_create(&th1,NULL,thfun1,NULL);
pthread_create(&th2,NULL,thfun2,NULL);
pthread_join(th1,NULL);
pthread_join(th2,NULL);
sem_close(&t);
return 0;
}
打印结果如下:
abababababababababab
20200802 才发现原来在Ubuntu下运行的结果并没有交错运行的效果。而且实际使用的时候你没有办法预估一个线程执行时间,因此需要找其他办法。