赞
踩
目录
申请信号量
控制信号量
设置信号量(PV操作)
信号与信号量的关系,就如同老婆和老婆饼的关系,没有任何关系。
[1, 31]是普通信号,[34, 64]是实时信号
- #include <iostream>
- #include <unistd.h>
- using namespace std;
-
- int main()
- {
- while (1)
- {
- cout << "this is a process, pid = " << getpid() << endl;
- sleep(1);
- }
- return 0;
- }
键盘按键 ctrl C ---> os将ctrl+C解释为2号信号(SIGINT) ---> 进程终止
自定义捕捉方法
signal函数的调用,并不是自定义捕捉方法函数的直接调用
仅仅设置了对目标信号的捕捉方法,该方法并不一定会被调用
这个自定义捕捉方法只有收到了捕捉信号的时候才会被调用
- #include <iostream>
- #include <unistd.h>
- #include <signal.h>
- using namespace std;
-
- void Handler(int signo)
- {
- cout << "进程捕捉到了一个信号,信号编号是:" << signo << endl;
- }
-
- int main()
- {
- signal(2, Handler);
-
- while (1)
- {
- cout << "this is a process, pid = " << getpid() << endl;
- sleep(1);
- }
- return 0;
- }
当自定义2号信号(SIGINT)的捕捉方法之后,进程收到2号信号并不会终止,而是执行自定义捕捉方法的打印函数
mykill.cc
- #include <iostream>
- #include <unistd.h>
- #include <signal.h>
- #include <cstdio>
- using namespace std;
-
- static void Usage(const string& proc)
- {
- cout << "\nUsage: " << proc << "pid signo\n" << endl;
- }
-
- void Handler(int signo)
- {
- cout << "进程捕捉到了一个信号,信号编号是:" << signo << endl;
- }
-
- int main(int argc, char* argv[])
- {
- if (argc != 3)
- {
- Usage(argv[0]);
- exit(1);
- }
- pid_t pid = atoi(argv[1]);
- int signo = atoi(argv[2]);
- int n = kill(pid, signo);
- if (n != 0)
- perror("kill");
-
- return 0;
- }
test.cc 一个死循环进程
- #include <iostream>
- #include <sys/types.h>
- #include <unistd.h>
- using namespace std;
-
- int main()
- {
- while (true)
- {
- cout << "我是一个正在运行的进程,pid:" << getpid() << endl;
- sleep(1);
- }
- return 0;
- }
myraise.cc
- #include <iostream>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <cstdio>
- using namespace std;
-
- int main()
- {
- int cnt = 0;
- while (true)
- {
- printf("cnt: %d\n", cnt++);
- sleep(1);
- if (cnt >= 5)
- {
- raise(9);
- //abort();
- }
- }
- return 0;
- }
5s后进程被自己发送的信号杀死(或放弃)
SIGFPE
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- using namespace std;
-
- int main()
- {
- while (true)
- {
- cout << "我在运行中..." << endl;
- sleep(1);
- int a = 10;
- a /= 0;
- }
-
- return 0;
- }
除0 浮点数错误SIGFPE
获取信号编号
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- using namespace std;
-
- void CatchSig(int signo)
- {
- cout << "获取一个信号,信号编号是:" << signo << endl;
- sleep(1);
- }
-
- int main()
- {
- signal(SIGFPE, CatchSig);
-
- while (true)
- {
- cout << "我在运行中..." << endl;
- sleep(1);
- int a = 10;
- a /= 0; //除0 浮点数报错
- }
-
- return 0;
- }
设置闹钟,进程1s之后结束,统计cnt累加次数
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- using namespace std;
-
- int main()
- {
- alarm(1);
- int cnt = 0;
- while (1)
- {
- cout << "cnt: " << cnt++ << endl;
- }
-
- return 0;
- }
将cnt定义为全局重新,用捕捉信号重新定义
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- #include <cstdlib>
- using namespace std;
-
- int cnt = 0;
-
- void CatchSig(int signo)
- {
- cout << "cnt: " << cnt << endl;
- }
-
- int main(int argc, char* argv[])
- {
- signal(SIGALRM, CatchSig);
- alarm(1);
- while (1)
- {
- cnt++;
- }
-
- return 0;
- }
由此可见计算机将数据从内存打印到外设时间损耗巨大,IO效率很低
闹钟是一次性闹钟,执行之后不再执行
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- #include <cstdlib>
- using namespace std;
-
- static int cnt = 0;
-
- void CatchSig(int signo)
- {
- cout << "cnt: " << cnt << endl;
- alarm(1);
- }
-
- int main(int argc, char* argv[])
- {
- signal(SIGALRM, CatchSig);
- alarm(1);
- while (1)
- cnt++;
-
- return 0;
- }
任何一个进程都可以通过alarm()系统调用设置闹钟,操作系统如何管理闹钟?先描述,再组织
核心转储
部分服务器默认关闭了核心转储
- #include <iostream>
- using namespace std;
-
- int main(int argc, char* argv[])
- {
- //核心转储
- while (1)
- {
- int a[10];
- a[100000] = 100;
- }
-
- return 0;
- }
越界访问,不仅报了段错误,还生成了core.30202文件
以Term退出的没有核心转储
核心转储:当进程出现异常的时候,将进程在对应的时刻,在内存中的数据转储到磁盘中
核心转储意义:支持调试(事后调试)
对所有信号做自定义捕捉测试
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- #include <cstdlib>
- #include <sys/types.h>
- using namespace std;
-
- void CatchSig(int signo)
- {
- cout << "收到一个信号,信号编号是:" << signo << endl;
- }
-
- int main(int argc, char* argv[])
- {
- for (int signo = 31; signo >= 1; --signo)
- signal(signo, CatchSig);
-
- while (1)
- {
- cout << "我在运行, pid = " << getpid() << endl;
- sleep(1);
- }
- return 0;
- }
只有9号信号可杀死进程(9号进程由os直接控制,禁止对9号信号做捕捉)
每个信号都有两个标志位表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作
如果一个信号没有产生,可以预先将它设为阻塞状态
信号产生的时候,不会被立即处理,而是在从内核态返回用户态的时候进行处理
用户想要访问内核或硬件资源,必须通过系统调用完成访问
CPU中存在CR3表态寄存器,表示当前运行的运行级别:0表示内核态,3表示用户态
每一个进程都有自己的地址空间(用户空间独占)、内核空间(被映射到每一个进程的3~4G)
进程要访问OS的接口,只需要在自己的地址空间上进行跳转
每一个进程都会共享一个内核级页表,无论进程如何切换,不会更改内核空间
系统调用接口,起始位置会将我们的用户权限更改为内核态(陷入内核)
特定的身份调用特定的代码,内核态也无法直接调用用户态状态
信号捕捉流程图
sigprocmask读取或更改进程的信号屏蔽字
sigpending获取进程的pending位图
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- #include <cstdlib>
- #include <sys/types.h>
- #include <vector>
- using namespace std;
-
- static vector<int> sigarr = {2, 3};
-
- void ShowPending(const sigset_t& pending)
- {
- for (int signo = 31; signo >= 1; signo--) {
- if (sigismember(&pending, signo))
- cout << "1";
- else
- cout << "0";
- }
- cout << endl;
- }
-
- void MyHandler(int signo)
- {
- cout << signo << " 号信号已经被递达\n" << endl;
- }
-
- int main(int argc, char* argv[])
- {
- for (const auto& e : sigarr)
- signal(e, MyHandler);
-
- // 1. 屏蔽指定的信号
- sigset_t block, oblock, pending;
- // 1.1 初始化
- sigemptyset(&block);
- sigemptyset(&oblock);
- // 1.2 添加要屏蔽的信号
- for (const auto& e : sigarr)
- sigaddset(&block, e); // 2号信号
- // 1.3 开始屏蔽
- sigprocmask(SIG_SETMASK, &block, &oblock);
-
- // 2. 遍历打印pending信号集
- int cnt = 10;
- while (1)
- {
- sigemptyset(&pending);
- sigpending(&pending);
- ShowPending(pending);
- sleep(1);
- if (cnt-- == 0)
- {
- cout << "恢复对信号的屏蔽\n" << endl;
- sigprocmask(SIG_SETMASK, &oblock, &block);
- }
- }
-
- return 0;
- }
将2号、3号信号屏蔽
ctrl C + ctrl \ 发送2号信号和3号信号,信号未决,pending位图2号和3号bit位置1
10s后重置对信号的屏蔽,os直接将重置的信号递达,捕捉到2号、3号信号
sigaction
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <vector>
- using namespace std;
-
- void ShowPending(const sigset_t& pending)
- {
- for (int signo = 31; signo >= 1; signo--)
- {
- if (sigismember(&pending, signo))
- cout << "1";
- else
- cout << "0";
- }
- cout << endl;
- }
-
- void MyHandler(int signo)
- {
- cout << "get a signo: " << signo << endl;
- }
-
- int main(int argc, char* argv[])
- {
- struct sigaction act, oact;
- act.sa_handler = MyHandler;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT, &act, &oact);
-
- while (true);
-
- return 0;
- }
进程串行处理同类信号
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cstdio>
- #include <cstdlib>
- using namespace std;
-
- void Count(int cnt)
- {
- while (cnt)
- {
- printf("cnt: %d\n", cnt);
- fflush(stdout);
- cnt--;
- sleep(1);
- }
- }
-
- void MyHandler(int signo)
- {
- cout << "get a signo: " << signo << endl;
- Count(10);
- }
-
- int main(int argc, char* argv[])
- {
- struct sigaction act, oact;
- act.sa_handler = MyHandler;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaddset(&act.sa_mask, 3); //在2号信号捕捉期间,屏蔽3号信号
- sigaction(SIGINT, &act, &oact);
-
- while (true) sleep(1);
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。