商业网站开发实训报告总结,做视频链接哪个网站没有广告,国外网站能否做百科参考资料,建筑设计网址大全目录 一、概念
二、前台进程与后台进程
1.ctrlc
2.ctrlz
三、信号的产生方式
1.键盘输入产生信号
2.系统调用发送信号
2.1 kill()函数
2.2 raise()函数
2.3 abort()函数
3.异常导致信号产生
3.1 除0异常
3.2 段错误异常
4.软件条件产生信号
4.1 管道
4.2 闹钟…目录 一、概念
二、前台进程与后台进程
1.ctrlc
2.ctrlz
三、信号的产生方式
1.键盘输入产生信号
2.系统调用发送信号
2.1 kill()函数
2.2 raise()函数
2.3 abort()函数
3.异常导致信号产生
3.1 除0异常
3.2 段错误异常
4.软件条件产生信号
4.1 管道
4.2 闹钟
四、核心转储
总结 一、概念
生活中我们也经常遇到信号比如早八的闹钟、红绿灯、鲁大师在电脑里面抽烟、周杰伦的到底有谁知道~是几点的方向~你~才~会~收~到~暗~号~。在信号还没有产生的时候我们已经知道什么样的信号需要如何去处理比如早八的闹钟在闹钟响之前我们就知道早上要么起床去上课要么把闹钟一关继续睡觉。
信号产生了我们不一定要立即处理他而是在合适的时候处理。比如你肚子疼需要拉肚子但是游戏已经开了对抗路已经在操作了今天不管你有本事就拉裤兜必须先把这把打完再去。因此我们要对信号进行暂时保存。
同时我们并不清楚具体什么时候肚子痛因此信号到来相对于我现在正在打的游戏是异步多执行流同时进行操作的。 小总结 我们能识别信号同时知道该如何处理 信号是异步的 可以对信号进行暂时保存 在合适的时候处理信号 信号是向目标进程发送消息通知的一种机制。
二、前台进程与后台进程
1.ctrlc
进程在运行时一般都是前台进程如下代码./mytest运行起来我们输入命令没用反应但我们运行时输入ctrlc可以终止掉进程。 如果我们执行的时候在后面加上 就让进程在后台运行此时输入命令可以反应但是进程不能被ctrlc终止。 这是因为前台进程只能有一个后台进程可以有多个由于shell也是一个进程因此当进程在前台运行时shell需要退入到后台进程中去因此无法接受指令。而你现在输入ctrlc终止进程就是让前台进程终止自然进程就结束了。 而当你进程以后台方式启动时前台进程是shell因此输入指令可以有结果如果你输入ctrlcshell自己会保护自己无法被ctrlc终止后台进程并没有收到ctrlc因此无法终止后台进程。 之前我们提到后台进程可以有多个比如现在我们重定向到log1.txt与log2.txt输入指令jobs可以看到后台进程的运行情况。 他们在后台运行并不影响前台shell接受指令同时ctrlc也无法终止。 我们输入fg number就可以将后台进程提到前台来输入ctrlc就可以终止掉该进程了。 小总结判断是前台进程还是后台进程看shell有没有能力接受用户输入有就是后台进程没有就是前台进程。
2.ctrlz
输入ctrlz可以暂停前台进程但是被暂停的进程会自动放到后台也就是我输入指令命令行能接受了。 现在我们输入 bgnumber 就可以将暂停的后台进程继续运行。 小总结 ./mytest 让进程在后台运行jobs 查看后台进程fg number 将后台进程放到前台ctrlz 暂停前台进程并放到后台bg number 将暂停的后台进程继续执行 三、信号的产生方式
1.键盘输入产生信号
在上面我们学习ctrlc终止前台进程其实ctrlc的本质上就是信号他是信号表中的2号信号。 我们可以通过写代码的方式来查看该现象。 signal函数能将收到的信号做自定义处理 参数1信号num参数2返回值为void参数为int的函数指针 #includeiostream
#includeunistd.h
#includesignal.husing namespace std;void sighandler(int signo)
{cout收到了signo号信号endl;exit(1);
}int main()
{signal(2,sighandler);while(1){coutpid: getpid()endl;sleep(1);}
}
运行后发现输入ctrlc会打印出内容同时发送2号指令也会打印出相同的内容由此可见ctrlc 等价于发送2号信号 。也就是键盘输入可以产生信号。 我们知其然还要知其所以然。我们在键盘中输入ctrlc会被操作系统接受到你的输入因为操作系统是进程的管理者他判断出你输入的内容是终止信号同时是输入给当前运行的前台进程的。那么操作系统肯定需要告诉进程信号到来了你赶紧处理。在进程的角度来看进程一定要通过存储来表示自己是否收到信号收到了哪种信号。这完全可以通过位图来实现比特位的位置代表收到的哪种信号比特为的内容0/1代表是否收到信号。由于普通信号只有1-31个因此用32位的整形变量就可以判断了。 我们之前提到在信号没有到来时进程就已经知道该如何处理相关信号因此进程还得有一张自己的函数指针数组数组的下标与信号的编号相关于是当发现信号位图中有信号的到来知道是哪一张信号然后会调用信号相关的函数进行执行。 操作系统向目标进程发送信号其实本质上是写信号将该进程信号位图的相关位置设置为1 那么既然ctrlc是一个信号之前我们学过的ctrlz也应该是信号咯。当然没错ctrlz是20号信号SIGTSTP。还有ctrl\是3号信号 跟之前一样使用signal捕获一下2号信号3号信号和20号信号。 9号信号不可被自定义捕捉因为操作系统得有能力杀死任意进程如果某个进程是恶意进程一直在读取你的数据或者对操作系统做破坏那么该进程捕捉了所有信号岂不是杀不掉了因此操作系统设置9号信号不可被捕捉。 2.系统调用发送信号
2.1 kill()函数
有一个kill的系统调用函数他可以往指定的进程发送指定信号。我们可以通过该函数来发送信号。 kill给指定进程发送信号 参数1进程pid参数2信号编号 代码如下
#includeiostream
#includeunistd.h
#includesignal.h
#includestringusing namespace std;void Usage(const string proc)
{cout\n Usage: proc -signumber processendl;
}int main(int argc,char* argv[])
{if(argc!3){Usage(argv[0]);exit(0);}int signumber stoi(argv[1]1);int processpid stoi(argv[2]);kill(processpid,signumber);
} 我们就可以利用kill函数给他传信号与进程pid即可将信号发送给此进程。 2.2 raise()函数
kill是给任意进程发送任意信号而raise是给自己发送任意信号 kill给指定进程发送信号 参数1信号编号 使用很简单如下raise2代表给自己发送2号信号 因为我们自定义捕捉了因此会一直收到2号信号。 2.3 abort()函数 给自己发送abort信号是6号信号参数返回值都不管直接调用即可。 我们发现进程确实收到了6号信号我们sighandler里面并没有让进程退出但是进程却被Aborted终止这是abort函数的特点就是进程收到6号信号你可以自定义捕捉但捕捉完毕我仍然会终止。 3.异常导致信号产生
C我们学过异常发生异常了代码并不会再往后面执行而是直接终止除非你捕获了异常。
3.1 除0异常
如下代码你发生了除0错误编译的时候就会警告当你执行的时候告诉你浮点数异常。这是8号信号 SIGFPE。 我们将信号捕捉运行我们并没有写循环按道理只会打印一次这里发现进程在一直打印消息。 这是因为进程在运行的时候会将进程中的数据放到CPU里面的寄存器去运行现在CPU运算发现了除0错误会给相应的标志位写上1记录你的错误操作系统就知道进程的错误了因为操作系统是软硬件资源的管理者那么操作系统需要发送对应信号干掉目标进程。 但是你自己的操作将信号自定义捕捉了杀死不了而后进程就切换了当进程又切换回来时操作系统又发现你对应的标志位为1因此又给你发送信号从此往复会一直发送信号却又杀不掉你。 3.2 段错误异常
我们写C/C代码的时候经常会遇到段错误。比如野指针越阶访问等等。段错误异常是11号信号SIGSEGV因此我们捕捉11号信号看看结果。 跟之前一样没有写循环依然一直报错。这是在访问虚拟内存页表时发现页表中没有对应内容虚拟到物理的映射。发生段错误标志位设置操作系统发送信号给进程进程收到信号并自定义捕捉进程切换又回到该进程发现标志位为1继续发送信号继续套娃。 4.软件条件产生信号
4.1 管道
我们之前在学习管道的时候当我们把读端关闭的时候写端会直接终止因为操作系统给写端发送SIGPIPE信号告诉写端兄弟别舔了她已经把你拉黑了。此时我们并没有涉及到寄存器或者其他硬件设备虽说有内存但是内存空间都是我自己开辟的呀我自己的东西我爱咋用咋用操作系统不会无缘无故给你发信号这就叫软件条件。
4.2 闹钟 alarm可以设置闹钟-给当前进程发送14号信号 参数设置几秒中后的闹钟 返回值正常返回0闹钟提前返回剩余时间。 在5次打印后收到了消息返回值为0。 综上产生信号的方式有很多但是发送信号只能由操作系统来完成也就是向进程PCB中的信号位图写入。
四、核心转储 首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁 盘上,文件名通常是core,这叫做Core Dump。 命令行输入指令 man 7 signal 往下翻可以查看信号的详细信息这里可以看到信号的动作有Term、Core、Ignignore、Contcontinue、Stop。 其他的都比较好理解比如Ign忽略Cont继续Stop暂停。但是还有Term和Core这两种我们学过的信号这两种类型都有他们都是终止进程有什么区别呢 我们发现Core中有SIGABRT、SIGFPE、SIGSEGV等等他们都比较像异常情况。报错的具体代码尚不清楚。需要用户进一步排查 而Term中的SIGINT键盘中断、SIGKILL杀死进程等等其实他们都没犯错 只是被杀掉了。结果很清楚 你的代码如果出现了Core类型的错误其实会发生core dump核心转储也就是在当前目录下多出一个以进程pid命名的 core.pid 文件。我们可以通过查看gbd查看代码具体报错位置信息。但是core dump功能是被默认关闭的。
输入指令ulimit -a可以查看系统的配置项其中第一项core file size就是core dump大小为0我们可以将他大小设置一下 输入指令ulimit -c size就可以更改core file size 的大小这是内存级别的也就是重启xshell会自动恢复。 现在再更改代码并运行就会发现多了core dumped发生了核心转储。 我们现在gdb调试mytest同时在gdb中输入core-file core.pid 此时就可以看到该文件是在具体哪个地方出错。 总结 信号的产生最终都要由操作系统来进行执行这是因为操作系统是进程的管理者。进程在信号到来不会立即处理而是在合适的时候处理。由于信号不会被立即处理因此信号需要暂时被进程记录下来记录在信号位图中。信号在没有收到信号的时候已经知道自己该如何处理信号。操作系统向进程发送信号本质是向目标进程的信号位图中写信号(置1)。 下一章信号的保存与处理