shell有一些内建命令,收到命令行字符串之后,首先检查是否时内置命令,如果是,则直接执行;如果不是,则认为命令行是需要执行的可执行文件,直接fork-exec执行。通过这样的方式达到可扩展的优势。
信号是一小条消息,通知进程系统中发生了一个某种类型的事件。是完全由软件基于异常机制实现的。
──────────────────────────────────────────────────────────────
SIGHUP 1 Term Hangup detected on controlling terminal
or death of controlling process
SIGINT 2 Term Interrupt from keyboard(ctrl-c)
SIGQUIT 3 Core Quit from keyboard
SIGILL 4 Core Illegal Instruction
SIGABRT 6 Core Abort signal from abort(3)
SIGFPE 8 Core Floating-point exception
SIGKILL 9 Term Kill signal-ctrl-c
SIGSEGV 11 Core Invalid memory reference-段错误
SIGPIPE 13 Term Broken pipe: write to pipe with no
SIGALRM 14 Term Timer signal from alarm(2)(用户自己使用)
SIGTERM 15 Term Termination signal
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated
SIGCONT 19,18,25 Cont Continue if stopped
SIGSTOP 17,19,23 Stop Stop process(ctrl-z)
SIGTSTP 18,20,24 Stop Stop typed at terminal
SIGTTIN 21,21,26 Stop Terminal input for background process
SIGTTOU 22,22,27 Stop Terminal output for background process
The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
使用int signal(int signum, isghandler_t handler);可以设置每个信号的关联行为。
同一时刻,只能有一个相同类型的等待处理的信号。如果同时又来了一个相同类型的信号,则后来的信号会被丢弃掉(原因是在一个进程中,一个信号的有效只用一个bit来表示 32bit int)。
进程可以阻塞信号的接收(没办法阻止信号的传递),即阻止进程在接收到信号之后的反应,使用系统调用sigpromask(相当于对进程的不同信号屏蔽位置位32bit int)。
进程组:每个进程都只属于一个进程组,默认情况下,子进程和父进程同属于一个进程组。
kill -9 12345 //杀死pid为12345的进程
kill -9 -12345 //杀死pgid为12345的每一个进程
2. 通过键盘发送信号:ctrl-c对应SIGINT,ctrl-z对应SIGSTOP,fg对应将所有被挂起的命令恢复到前台执行。
pause系统调用:阻塞直到一个信号到来,执行完信号处理动作后返回。
进程A正在执行时,来了一个信号SIGA,只是信号标志位置位,还没来得及执行,这时执行了一次上下文切换,系统调度进程B。过了一段时间,系统又进行上下文切换,调度进程A,这是由于信号标志位置位,所以开始执行信号处理函数(用户态),执行完成之后,切换回进程A的主进程,这两步之间还有依次用户态-内核态-用户态的切换。
https://blog.csdn.net/zhangchaoq/article/details/51201979
2. 只能使用异步信号安全的函数(printf,sprinf,malloc,exit都不是异步信号安全的);
5. 主函数和信号处理函数公用的变量声明为volatile类型,避免编译器把它存储在寄存器中;
6. 使用sig_atomic_t(多数系统上是int)声明主函数和信号处理函数之间的标志,对这种类型的操作是原子的(不会被打断的过程中)。
1. 执行一次信号处理函数后,会自动恢复默认操作,所以需要每次执行完信号处理函数后,重新挂载一次;
2. 有些unix上,如果执行read这种慢系统调用,还没有返回时,系统自动结束系统调用,并把errno置为EINTR,需要用户检查errno并重新执行系统调用。
大概原理:addjob和deljob在一个进程中,都在父进程中。只能按次序执行。父进程在执行fork之前已经把SIGCHLD屏蔽了,直到addjob之后,才会解除屏蔽。因此addjob只可能在deljob之前调用。