被多个进程能够看到看到额资源叫做临界资源
如果没有堆临界资源进任何的保护,对于临界资源的访问,双方访问都是乱序的,可能会因为读写交叉导致的各种乱码,废弃数据/访问控制方面的问题
对多个进程而言,访问临界资源的代码叫做临界区,比如二个访问共享内存的那一句代码
我们把一件事情,要么没做,要么做了,没有中间状态,我们叫做原子性
任何时刻,只允许一个进程,访问临界资源,这个我们叫做互斥
信号量的本质是计数器
比如你去电影院看电影,电影院可以给多个人访问,我们叫临界资源,电影院只有100个座位,代表了只能有100张票,,因为多了的话就会的座位发生冲突
那么你怎么证明,放映厅里面特定的座位是你的,那么肯定是我买到了票,这个座位就是我的,那么买票的本质是对放映厅中特定的座位的一种,预定机制,那么你不去也没人坐,理想状态,人可能一样会坐,但是计算机里面的数据不会,那么怎么防止卖票卖多了,只要我们设定了一个值int count = 100,卖到了一张就count–,如果count为零就不卖,等有没有人退票或者电影看完下一场,买票的过程要保证原子性,比如一开始有个进程执行操作,操作到一半,发生进程切换换成另一个进程直接买50张票,买完50张票count-- 50次进程退出,回到最开始的那个进程,他又把count改回了100,那么这样就会因为进程交叉,而出现的数据错误,所以我们要保证原子性
总结
信号量是一个计时器,这个计时器对应的操作是原子的
比如红绿灯,闹钟等等,我们要先能识别信号的能力,比如绿灯行,红灯停,闹钟醒了就起床,所以我们要能识别信号所表达的意思,还有闹钟,我们设置闹钟的时候我们早就知道了信号产生之后要做什么,即便当前信号还没产生,也就是闹钟还没响,而这个是叫做提前知道信号的处理方法,而我们知道信号所表达的意思和提前知道信号的处理方法,具备了这二种我们就有了处理特定信号的能力
那么我们把现实情况带入进程和信号
信号是进程发送得,所以进程要具备处理信号的能力
1.该能力一定是预先早就已经有了
2.进程能够识别对应的信号
3.进程能够处理对应的信号
#include
#include
int main()
{
while(1)
{
sleep(1);
}
return 0;
}
我们来运行下面代码

ctrl + c 把进程终止掉

./myproc & //把当前进程添加到后台进程

jobs查看后台进程

fg 1 查找后台任务,把1放在前台任务,我们在ctrl+c,那么他就没终止了


如果你想要关闭后台进程,但是你后悔了那么就ctrl + z 这个时候我们调用jobs命令看到进程属于停止状态,我们bg 加进程号,他就恢复了运行状态了
因为信号产生时异步,当信号产生的时候,对应的进程可能正在做更重要的事情,我们进程可以暂时不处理这个信号,但是你必须要记住这个信号已经来了,等他完成了手上的事在来处理这个信号,
而信号的处理分分三种处理方式
1.默认动作 你送给你女朋友一个小礼物(处于热恋中),你女朋友表示很高兴
2.忽略 你和你女朋友发生了冷战,那么你再送给他礼物,他忽略你
3.自定义动作 和不同的人有不同的对应方式
而上面这种叫做信号的处理,专业点叫信号的捕捉
ctrl c ctrl z ctrl d 等等就是产生信号 ctrl + c就是向前台产生2信号
kill -l看信号

那么我们怎么证明是发送2号信号

signum,给特定信号设置捕捉动作,第二个参数是函数指针,可以自定义动作的函数指针
#include
#include
#include
using namespace std;
void handler(int signo)
{
cout<<"我是一个进程,刚刚获取了一个信号: "<< signo <<endl;
}
int main()
{
signal(SIGINT,handler);
sleep(3);
while(true)
{
cout<<"我是一个正在运行的进程 "<< getpid() <<endl;
sleep(1);
}
return 0;
}
可以看到我输入了ctrl + c,他就发出了信号是二,这里要注意的是,handler这里只是设置了,是SIGINT出信号了,才调用handler函数,如果没有信号了,那么永远都不会使用handler函数

用户层产生信号的方式,键盘产生,操作系统给进程发送(写入)信号
除了使用键盘发送信号,我们还能通过函数来发送信号
通过kill函数来发送信号
kill有二个参数,第一个是要发送的pid,第二个参数是发送的信号
发送信号失败错误返回-1
mykill.cc
#include
#include
#include
#include
#include
#include
#include
using namespace std;
static