当前位置: 首页 > Linux

linux系统编程-信号量

时间:2023-04-06 04:19:50 Linux

大家都知道互斥量可以用于线程间的同步,但是一次只能有一个线程抢到互斥量,限制了程序的并发释放。如果我们要让多个线程同时访问同一个资源,就没有办法使用互斥锁了。只有互斥锁会锁住整个共享资源,只允许一个线程访问它。这种现象使得线程轮流运行,即线程从并行执行变为串行执行,这与直接使用单进程没有区别。因此,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_post时,信号量会加1,同时唤醒阻塞在某个信号量上的线程。由于上述线程的加减法对用户隐藏了sem_t的实现,所以这两个操作只能通过函数实现,不能直接使用++和--符号进行操作。sem_init函数函数原型:intsem_init(sem_t*sem,intpshared,unsignedintvalue);函数功能:初始化一个信号量;参数说明:sem:信号量;pshared:设置为0时,信号量用于线程间同步;当不为0(通常为1)时,用于进程间同步;value:指定信号量的初值,信号量的初值决定了允许同时占用信号量的线程数。sem_destroy函数函数原型:intsem_destroy(sem_t*sem);函数功能:销毁一个信号量sem_wait函数函数原型:intsem_wait(sem_t*sem);function函数:给信号量值加一个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);//producer会清空cells的个数--,如果为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",queue[i]);队列[i]=0;//消费一个产品sem_post(&blank_number);//consume以后空单元格的个数++i=(i+1)%NUM;睡眠(兰德()%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,消费者,NULL);pthread_join(pid,NULL);pthread_join(cid,NULL);sem_destroy(&blank_number);sem_destroy(&product_number);return0;}运行结果:更多精彩内容请关注公众号良旭Linux,在公众号回复1024可免费获得5T技术资料,包括:Linux、C/C++、Python、树莓派、嵌入式、Java、人工智能等公众号回复群,邀您加入专家云技术交流群。最后,最近有很多朋友找我要一份Linux学习路线图,所以我结合自己的经验,利用业余时间熬夜一个月,整理了一本电子书。无论你是面试还是自我提升,相信都会对你有所帮助!免费送给大家,只求大家给我点个赞!电子书|LinuxDevelopmentLearningRoadmap也希望有小伙伴可以加入我的行列,把这本电子书做得更加完美!获得?希望老铁们来个三连击,让更多人看到这篇文章。推荐阅读:干货|程序员和高级架构师免费发送工件的必备资源|支持搜索的资源网站