文章目录
什么叫做信号呢?
生活当中认为是信号的是:红绿灯 闹钟 下课铃 鸡叫 手势
1.当红灯亮的时候, 你会停下来 即匹配的动作
那为什么会有这个匹配动作呢?
因为曾经有人培养过你
所以信号没有被产生,也知道怎么该处理它
2.我们能够认识并处理一个信号,是能因为识别这个信号的
若进程就是我,信号就是一个数字,进程在没有接收信号的时候,它早就知道一个信号该如何处理了
程序员在设计进程的时候,早就已经设计了对信号的识别能力
3.因为信号可能随时产生,所以在信号产生前,我可能正在做优先级更高的事情,我可能不能立马处理信号
要在后续合适的时候进行处理
如:你点了一份外卖,因为你不确定外卖什么时候到,所以开了一把游戏,当外卖小哥给你打电话说外卖到了时,游戏还没打完,所以你跟外卖小哥说等一会,马上到,然后继续打游戏,直到游戏打完,才去取外卖
在信号产生和信号处理之间,存在时间窗口,因为没办法直接处理,需要等待后续处理
在时间窗口期间,需要被保存起来
进程收到信号的时候,如果没有立马处理这个信号,需要进程具有记录信号的能力
信号的产生对于进程来讲是异步的
异步为两者互相做自己的事,互不干扰
如:你正在上课,外卖小哥给你打电话告诉你快递到了,因为快递有重要的东西,所以你不得不现在去取,但是在你取快递的过程中,依旧在上课,上课与你取快递两件事情互不干扰
进程该如何记录对应产生的信号?记录在哪里?
可能同时收到很多信号,已经被产生但尚未处理,所以需要在时间窗口内,将这些信号保存,同时也应该将其进行管理
而管理的本质是先描述,在组织
那如何描述一个信号呢? 用什么数据结构管理这个信号呢?
输入 kill -l 查看信号列表
可以发现在31 和34之间没有信号存在,说明信号被划分为两部分,1-31以及34-64
34-64称之为实时信号,
1-31称之为普通信号,是目前要学习的信号
数字实际上是真正的信号,而大写的名称是宏
实时操作系统
当前主流的操作系统分为实时和分时,
分时像Linux、windows操作系统,基于时间片操作器调度的,强调的是公平调度
实时 像汽车的车载系统的辅助驾驶
特点为若来一个任务,就必须优先级较高的将该任务立马处理,强调的是高响应
普通信号 ,只保存有无产生,只需在合适的时候处理信号即可
可以通过0代表没有产生,1代表产生
1-31刚好是32个比特位,所以使用位图结构管理信号
而进程使用task_struct(PCB) 内部必定要存在一个位图结构,用int表示

从低到高的比特位,依次对应1-31 信号
发送信号的本质是写入信号,直接修改特定进程的信号位图中的特定比特位,0变成1即可
比特位的位置,称之为信号的编号
比特位的内容,表示是否收到该信号
默认处理信号的方式:
1.默认动作
2.忽略信号
3.用户自定义动作
如:拿到快递,共有三种选择
1.执行默认动作把快递打开 2.忽略快递 3. 执行自定义动作(如快递内是零食,送给你的女朋友)
在vscode中,创建makefile文件
mysignal:mysignal.cc
g++ -o $@ $^
.PHONY:clean
clean:
rm -f mysignal
创建 mysignal.cc(以cc结尾是cpp) 文件
会一直循环打印一句话,并当前进程的包含pid值
#include<iostream>
#include<unistd.h>
using namespace std;
int main()
{
while(true)
{
cout<<"我是一个进程,我正在运行...,pid值:"<<getpid()<<endl;
sleep(1);
}
return 0;
}
复制SSH渠道创建终端2,在保证运行终端1的可执行程序的情况下,
在终端2中输入 kill -9 +pid值 ,终止了终端1中运行的程序

实际上 在键盘中输入 CTRL C ,终止运行程序,本质也是向对前台进程发送信号
Linux通过远程终端访问时,只允许一个进程处于前台,默认情况是bash,
所以在自己的程序运行时输入指令没有任何反应
输入 man 2 signal 指令
第二个是一个函数指针 将 void(*) (int) typedef 命名为 sighandler_t
signal 函数的第一个参数 是 signsum 代表信号编号
第二个参数 是 handler 代表哪一个进程调用了signal,使指定信号不在执行默认动作,而是执行该函数指针指向的方法
输入 CTRL C 相当于发送 2号信号
修改 mysignal.cc文件内容,并运行程序 发现输入 CTRL C 指令无法结束程序


同样在终端2中输入 kill -2 pid值,也无法结束运行程序
说明对于2号信号 ,进程的默认方法是终止进程
signal 可以进行对指定动作的信号设定自定义处理动作
当signal(2,handler)调用完这个函数时, handler方法没有被调用,只是发生了回调
handler作为函数的地址传过去 作为参数被函数指针接收,再通过函数指针找到handler函数 完成调用
在操作系统内部,把对应的自定义方法的地址保存起来了
handler方法什么时候被调用?
当2号信号产生的时候
如: 你小时候总喜欢在家里调皮,你老爸不管你,认为这是很正常的事情,所以你认为这是默认动作,但是你的老妈看见你调皮,就告诉你说如果下次再看见你调皮,就揍你,
所以再有调皮捣蛋事情发生,不会像你老爸那样什么都不管,你老妈会揍你
是在下次调皮发生的时候,才揍你
默认对2号信号的处理动作:终止进程
输入 man 7 signal 指令
2号信号的动作是 Term(终止)
用signal(2,handler),是在执行用户动作的自定义捕捉
CTRL \ 代表3号信号 ,此时虽然2号信号被置为自定义动作了,但是三号信号还没有,所以依旧能终止进程
修改mysignal.cc文件内容,加入对于3号信号的自定义动作
再次运行可执行程序时,发现使用CTRL \ 也会调用自定义动作
可以给所有信号设置同一个处理函数
若修改mysignal.cc文件内容,将1-31的所有普通信号都进行自定义动作捕捉

可当运行可执行程序时,在终端2中使用 kill -9 pid值 方式依旧可以干掉进程
9号信号被称为管理员信号,不可被自定义,只能执行默认动作
在输入的时候,计算机怎么知道从键盘输入数据了呢?
键盘是通过硬件中断的方式,通知系统键盘已经按下了

CPU存在很多针脚,有自己的编号,接到主板上
键盘是通过中断控制器(如8259)连接到CPU的,
当按键盘中的某个位置时,操作系统要知道是哪个设备按下的(磁盘 键盘 网卡)
键盘通过中断控制器链接到9号阵脚处,触发中断
而从这个阵脚的数字被叫做 中断号
CPU内部有各种寄存器,当阵脚有数字时已经就绪时,向CPU寄存器的内部写数字
就完成了硬件中断
操作系统内维护一张中断向量表
中断向量表内部包含函数指针
中断号作为中断向量表的下标,直接调用中断向量表中对应的方法
而这个方法会从键盘中读取数据
输入 man 2 kill 指令
第一个参数为目标进程
第二个参数为信号
向目标进程(pid)发送对应的信号(sig)
成功返回0,失败返回-1
命令行参数
main函数的两个参数,char* argv[] 为指针数组 ,argv为一张表,包含一个个指针,指针指向字符串
int argc,argc为数组的元素个数
创建mykill.cc文件
当输入./mykill时,由于有命令行参数的存在,将其放入数组下标为0的位置中,同时数组个数为0
所以进入自定义的用户手册
修改mykill.cc文件内容
c由于agrv是字符指针数组,而我们想要的目标进程和信号编号都是数字,所以需要使用atoi函数,将字符串转化为整数
创建loop.cc文件
运行loop.cc与mykill.cc文件,形成可执行程序

在终端1中运行loop
在终端2中运行输入 ./mykill 9 对应进程的pid值
9为进程编号 pid值为目标进程
输入loop进程的pid值,从而使用9号信号结束loop进程
输入 man raise 指令
谁调用raise,就给谁发指定的信号
修改mykill.cc文件内容
再去调用可执行程序mykill时,自己就结束了,因为自己给自己发送2号信号
输入 man abort 指令
给自己发信号
再次修改mykill.cc文件内容
没有end存在,说明当前进程自己把自己干掉了
通过添加signal的方式,若运行mykill,自动生成get a signal :6
说明使用 Aborted时使用6号信号
而在实际运行时,会自动生成get a signal :6 ,说明实际上Aborted是使用6号信号
alarm函数可以设定一个未来时间
如:alarm(5) alarm函数调用完了,5秒后给当前进程发送SIGALRM(14)信号,该信号的默认动作是终止当前进程
alarm函数返回值是0或者以前设定的时间还余下的秒数
假设你想睡一觉,设定闹钟30分钟后响,但是在20分钟后你被吵醒了,你又重新设置闹钟15分钟后响
此时返回值就是上一次余下的10分钟
修改mykill.cc文件内容
计算1S中计算机会将整数累计到多少
在这次计算中,count只有11万多,非常不符合我们的预期
因为要打印到显示器上,以及网络问题,非常拖延速度
修改count为全局变量,在发送信号时,自定义方法中输出count值
这时count的值就变成5亿多
两者相比之下,说明IO效率非常底下
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(
我有一个应用程序正在从Ruby迁移到JRuby(由于需要通过Java提供更好的Web服务安全支持)。我使用的gem之一是daemons创建后台作业。问题在于它使用fork+exec来创建后台进程,但这对JRuby来说是禁忌。那么-是否有用于创建后台作业的替代gem/wrapper?我目前的想法是只从shell脚本调用rake并让rake任务永远运行......提前致谢,克里斯。更新我们目前正在使用几个与Java线程相关的包装器,即https://github.com/jmettraux/rufus-scheduler和https://github.com/philostler/acts
在尝试实现应用auto_orient的过程之后!对于我的图片,我收到此错误:ArgumentError(noimagesinthisimagelist):app/uploaders/image_uploader.rb:36:in`fix_exif_rotation'app/controllers/posts_controller.rb:12:in`create'Carrierwave在没有进程的情况下工作正常,但在添加进程后尝试上传图像时抛出错误。流程如下:process:fix_exif_rotationdeffix_exif_rotationmanipulate!do|image|
我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几
已检查ActiveRecord、DataMapper、Sequel:有些使用全局变量(静态变量)有些需要在使用模型加载源文件之前打开数据库连接。在使用不同数据库的sinatra应用程序中使用哪种ORM更好。 最佳答案 DataMapper专为多数据库使用而设计。你可以通过像DataMapper.setup(:repository_one,"mysql://localhost/my_db_name")这样的方式设置多个存储库。DataMapper随后会跟踪所有已在哈希中设置的存储库,您可以引用该哈希并将其用于范围界定:DataMapp