linux中信号量捕捉脚本,Linux学习笔记(15)-信号量(示例代码)

本文介绍了多线程编程中的同步和互斥问题,重点讲解了信号量作为解决机制的概念和操作,包括二值信号量和计数信号量。通过公共厕所和自家卫生间的比喻,解释了信号量的工作原理。文中还详细阐述了POSIX有名信号量的创建、关闭、操作以及删除,并提供了实战示例,展示了如何使用信号量实现进程间的同步。
摘要由CSDN通过智能技术生成

在多线程或者多进程编程中,有一个非常需要关注的东西,那就是同步以及互斥问题。

同步是指多个进程之间的协作,而互斥是指多个进程之间,为了争夺有限的资源,而进行的竞争。

理论很高端,但经过自己几天的学习,发现操作系统中,线程的信号量还是比较简单易懂的……

————————————————————————————————————————

信号量是用来解决线程间同步或互斥的一种机制,也是一个特殊的变量,变量的值代表着当前可以利用的资源。

如果等于0,那就意味着现在没有资源可用。

根据信号量的值可以将信号量分为二值信号量和计数信号量:

(计数信号量)就像一间公共厕所,里面一共有十个坑(最大是32767),算是十个资源。在同一时间可以容纳十个人,当满员的时候,外面的人必须等待里面的人出来,释放一个资源,然后才能在进一个,当他进去之后,厕所又满员了,外面的人还得继续等待……

(二值信号量)就像自己家的卫生间,一般只有一个马桶,在同一时间只能有一个人来用。

信号量只能进程两个原子操作,P操作和V操作,

概念:

原子操作,就是不能被更高等级中断抢夺优先的操作。

由于操作系统大部分时间处于开中断状态,所以,一个程序在执行的时候可能被优先级更高的线程中断。

而有些操作是不能被中断的,不然会出现无法还原的后果,这时候,这些操作就需要原子操作。就是不能被中断的操作。

P操作:如果有可用的资源(信号量>0),那么占用一个资源(信号量-1)。如果没有可用的资源(信号量=0),则进程被阻塞,直到系统重新给他分配资源。

V操作:如果在该信号量的等待队列中有进程在等待该资源,则唤醒一个进程,否则释放一个资源(信号量+1)

POSIX提供两种信号量,有名信号量和无名信号量,有名信号量一般是用在进程间同步,无名信号量一般用在线程间同步。

两种信号量的操作流程,大概有下面的几点不同:

b9b4825eb90a40b5a3b3691112f96e88.jpg

61da89c720ff46d8b7aec7d9cd01ce84.jpg

主要在于两种信号量初始化和销毁的方式不同。

对了,还有一点是非常需要注意的,和在操作共享内存时需要连接库一样,在编译信号量的时候,也需要加上-pthread参数。

————————————————————————————————————————————————————————————

首先先来学习有名信号量

创建有名信号量:

创建或者打开一个信号量,需要使用sem_open()函数,函数原形如下:

sem_t sem_open(const char * name, int oflag, mode_t mode, unsigned int value)

返回值sem_t 是一个结构,如果函数调用成功,则返回指向这个结构的指针,里面装着当前信号量的资源数。

参数name,就是信号量的名字,两个不同的进程通过同一个名字来进行信号量的传递。

参数oflag,当他是O_CREAT时,如果name给出的信号量不存在,那么创建,此时必须给出mode和vaule。当他是O_EXCL时,好像没有啥太重要的意义。

参数mode,很好理解,用来指定信号量的权限。

参数vaule,则是信号量的初始值。

关闭有名信号量:

关闭有名信号量所使用的函数是sem_close(sem_t *sem)

这个函数只有一个参数,意义也非常明显,就是指信号量的名字。

信号量操作:

前面已经说过,在使用信号量时,有两个非常重要的操作

P操作:使用的函数是sem_wait(sem_t *sem)

如果信号量的值大于零,sem_wait函数将信号量减一,并且立即返回。如果信号量的值小于零,那么该进程会被阻塞在原地。

V操作:使用的函数是sem_post(sem_t *sem)

当一个进程使用完某个信号量时,他应该调用sem_post函数来告诉系统收回资源。

sem_post函数和sem_wait函数的功能刚好相反,他会把指定的信号量加一

删除有名信号量:

当使用完有名信号后,需要调用函数sem_unlink来释放资源。

函数原形:int sem_unlink(const char *name)

——————————————————————————————————————————————————————————

实战演练!!!!

需求:创建两个进程,A进程打印A,然后等待B进程打印B,在B进程打印完了后,A进程在打印C。

A进程代码如下:

#include#include#include#include#include#include

#define SEM_NAME "name"

intmain()

{

sem_t*sem_test;sem_test= sem_open("ni", O_CREAT, 0644, 0);if(sem_test < 0)

{

printf("A进程创建信号量失败!errno=%d\\n",errno);

exit(-1);

}

printf("进程A进入等待……\\n");

printf("A\\n");

sem_wait(sem_test);

printf("C\\n");

sem_post(sem_test);

printf("A进程执行完毕!\\n");

sem_close(sem_test);

sem_unlink("ni");

return 0;

}

B进程代码如下:

#include#include#include#include#include#include

#define SEM_NAME "name"

intmain()

{

sem_t*sem_test;sem_test= sem_open("ni",0);if(sem_test < 0)

{

printf("B进程创建信号量失败!errno=%d\\n",errno);

exit(-1);

}

printf("B\\n");

sem_post(sem_test);

printf("B进程执行完毕!\\n");

sem_close(sem_test);

sem_unlink("ni");return 0;

}

现在进程编译(一定要记得在编译选项后加上-pthread哦!!)

9eb0a4b67eed4339b94f4dc0cf0c7c73.jpg

代码执行结果!!

9765b5cc91af44a7a040c45d2d878582.jpg

执行得很成功!!

值得一提的是,如果在执行中出现了段错误 (核心已转储)这种错误信息的话,最好是去/dev/shm/下看一下,看看是否有个黄色的文件,权限被设置的奇高!

我就遇到了这样的问题。

哎!虽然整篇文章就这么短短的几十行,但我可是足足奋斗了将近五个小时才搞懂!!

明天~继续加油!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值