当前位置: 首页 > 科技观察

linux系统编程-信号量

时间:2023-03-18 02:57:20 科技观察

大家都知道互斥量可以用于线程间的同步,但是一次只能有一个线程抢到互斥量,限制了程序的并发释放。如果我们要让多个线程同时访问同一个资源,就没有办法使用互斥锁了。只有互斥锁会锁住整个共享资源,只允许一个线程访问它。这种现象使得线程轮流运行,即线程从并行执行变为串行执行,这与直接使用单进程没有区别。因此,Linux系统提出了信号量的概念。这是一种比较折衷的处理方式,既能保证线程间的同步,数据不会混淆,又能提高线程的并发性。注意,这里说的信号量与我们学过的信号无关,就像Java与JavaScript无关一样。主要应用函数:sem_init函数sem_destroy函数sem_wait函数sem_trywait函数sem_timedwait函数sem_post函数以上六个函数的返回值分别为:成功返回0,失败返回-1,同时设置errno。细心的读者可能会注意到,它们没有pthread前缀,这意味着信号量不仅可以在线程之间使用,还可以在进程之间使用。sem_t数据类型本质上还是一个结构体。但是就像文件描述符一样,我们可以在应用过程中将其简单地视为一个整数,而忽略实现细节。用法:sem_tsem;我们约定信号量sem不能小于0,使用时注意包含头文件。与互斥量类似,信号量也有类似加锁和解锁的操作。sem_wait函数用于加锁,sem_post函数用于解锁。这两个函数有以下特点:调用sem_post时,如果信号量大于0,则信号量减一;当信号量等于0时,线程在调用sem_post时会被阻塞;唤醒阻塞在信号量上的线程。由于上述线程的加减法对用户隐藏了sem_t的实现,所以这两个操作只能通过函数实现,不能直接使用++和--符号进行操作。##sem_init函数原型:intsem_init(sem_t*sem,intpshared,unsignedintvalue);功能:初始化一个信号量;参数说明:sem:信号量;pshared:设置为0时,信号量用于线程间同步;当非零(通常为1)时,用于进程间同步;value:指定信号量的初值,信号量的初值决定了允许同时占用信号量的线程数。##sem_destroy函数函数原型:intsem_destroy(sem_t*sem);函数功能:销毁一个信号量##sem_wait函数函数原型:intsem_wait(sem_t*sem);函数功能:信号量值加一##sem_post函数函数原型:intsem_post(sem_t*sem);函数功能:信号量值减一##sem_trywait函数函数原型:intsem_trywait(sem_t*sem);函数功能:尝试锁定信号量,类似pthread_mutex_trylock;##sem_timedwait函数原型:intsem_timedwait(sem_tsem,conststructtimespecabs_timeout);功能:限时尝试锁定信号量参数说明:sem:semaphore;abs_timeout:同pthread_cond_timedwait,使用绝对时间。用法如下(例如设置超时为1秒):time_tcur=time(NULL);获取当前时间。结构timespect;定义timespec结构体变量tt.tv_sec=cur+1;计时1秒t.tv_nsec=t.tv_sec+100;sem_timedwait(&sem,&t);传参生产者消费者信号量模型:/*Semaphore实现生产者消费者问题*/#include#include#include#include#include#defineNUM5intqueue[NUM];//全局数组实现循环队列sem_tblank_number,product_number;//空信号量,积信号量void*producer(void*arg){inti=0;while(1){sem_wait(&blank_number);//生产者将空白单元格的个数--,如果为0则阻塞等待queue[i]=rand()%1000+1;//生产一个产品printf("----Produce---%d\n",queue[i]);sem_post(&product_number);//商品个数++i=(i+1)%NUM;//利用下标实现循环休眠(rand()%3);}}void*consumer(void*arg){inti=0;while(1){sem_wait(&product_number);//消费商品编号--如果为0则阻塞等待printf("-Consume---%d\n",队列[i]);queue[i]=0;//消费一个商品sem_post(&blank_number);//消费后放入空格数++i=(i+1)%NUM;sleep(rand()%3);}}intmain(intargc,char*argv[]){pthread_tpid,cid;sem_init(&blank_number,0,NUM);//初始化空白信号量为5sem_init(&product_number,0,0);//产品数量为0pthread_create(&pid,NULL,producer,NULL);pthread_create(&cid,NULL,consumer,NULL);pthread_join(pid,NULL);pthread_join(cid,NULL);sem_destroy(&blank_number);sem_destroy(&product_number);return0;}运行结果:本文经授权转载自公众号《良旭Linux》500强外企Linux开发工程师良旭,分享了大量Linux干货公众号有货,欢迎关注!