Linux下主要分为两种信号量,system-v和posix信号量,posix信号量又分为无名信号量和有名信号量,这里我们只分享无名信号量这里我们主要研究posix信号量。信号量是同步的一种方式,常常用于对共享资源的访问,举一个常见的例子,假如一个停车场有100个停车位,我们将车停在这个停车场需要看一下这个停车场还有多少车位可以停,此时空位就是一个信号量,每空一个车位,信号量+1,每次停一辆车时信号量-1.
(1)信号量会使等待资源线程进入休眠状态,所以适合于那些占用资源比较久的场合,比较车倒车状态的切换。
(2)在驱动中,信号量不可以用于中断中,原因是信号量会引起休眠状态,中断不能休眠。
(3)若共享资源的持有时间比较短,则不适合使用信号量,频繁的休眠,切换线程会导致开销远远大于信号量所带来的那点优势。
2.1 初始化
#include
int sem_init(sem_t *sem, int pshared,unsigned int value);
sem :信号量变量;
pshared:是否在多个进程中传递信号量,若不是则写为0;
value:该参数指定信号量的初始值。如果想要在两个进程之间使用信号量,需要确保sem参数指向两个进程之间共享的内存范围。
2.2 销毁
#include
int sem_destroy(sem_t *sem);
2.3 P操作
#include
int sem_trywait(sem_t *sem);
int sem_wait(sem_t *sem);
returns 0 on success;
on error,-1 is returned,
如果信号量的值大于0,则此时会将信号量的值减1,并且立刻返回,若当前信号量的值为0,那么sem_wait会导致线程阻塞,直到信号量的值大于0或者被信号中断才返回,而sem_trywait为非阻塞版本,当信号量为0时,该函数回-1并且将errno置为EAGAIN。
2.4 V操作
#include
int sem_post(sem_t *sem);
returns 0 on success;
on error,-1 is returned,
该函数用于给信号量计数+1,若此时用sem_wait阻塞的线程则被唤醒。
2.5 取值操作
#include
int sem_t getvalue(sem_t sem, int *val);
returns 0 on success;
on error,-1 is returned,
val返回的值
#include
#include
#include
#include
#include
sem_t g_sem;
void *ReadThreadFun(void *arg)
{
while(1)
{
printf("read 1 begin\n");
sem_wait(&g_sem);
printf("read 1 end\n");
}
}
void *WriteThreadFun(void *arg)
{
while(1)
{
sleep(1);
printf("write 1 begin\n");
sem_post(&g_sem);
printf("write 1 end\n");
}
}
int main(int argc,char **argv)
{
pthread_t pReadID;
pthread_t pWriteID;
int iRet;
iRet = sem_init(&g_sem,0,0);
if(iRet != 0)
{
printf("sem_init failed\n");
return 0;
}
iRet = pthread_create(&pReadID,NULL,ReadThreadFun,NULL);
if(iRet !=0 )
{
printf("ReadThreadFun create failed\n");
return -1;
}
iRet = pthread_create(&pWriteID,NULL,WriteThreadFun,NULL);
if(iRet !=0 )
{
printf("WriteThreadFun create failed\n");
return -1;
}
pthread_join(pReadID,NULL);
pthread_join(pWriteID,NULL);
sem_destroy(&g_sem);
return 0;
}
结果:
read 1 begin
write 1 begin
write 1 end
read 1 end
read 1 begin
write 1 begin
write 1 end
read 1 end
....
当read线程开始时,此时sem的值为0,阻塞此线程,write线程开始,此时sem的值变为0,解除线程阻塞,