目录
内核态和用户态
在系统中,用户或者OS自己,怎么知道当前处于内核态,还是用户态?
sigaction
可重入函数
volatile c语言关键字
SIGCHLD信号
内核态和用户态
系统调用表结构是属于操作系统的!
3GB--用户空间 1GB---内核空间
0.系统调用的过程,也是在进程地址空间上进行的!
所有的函数调用,都是地址空间之间的跳转
系统调用基于软中断完成
整个进程的地址空间0-3GB 用户区
一般用户访问0-3GB不需要任何系统调用
3-4GB内核区
只要拿到虚拟地址就能访问0-3GB的代码和数据了
根据页表从虚拟地址到物理地址的映射
操作系统也是软件,一定也在内存!
用户页表,会存在很多份
内核页表,系统只有一份,所有进程共享
0-4GB 是每个进程的"视野"
每个32位进程看到的"世界":
┌─────────────────────────────────┐ │ 进程视角:我拥有0-4GB的完整空间 │ │ 但实际上: │ │ • 0-3GB:我的私有空间 │ │ • 3-4GB:内核的共享空间 │ └─────────────────────────────────┘现实情况:
物理内存中同时有多个进程,每个都以为自己独占0-4GB
0-4GB是每个进程的虚拟地址空间范围,不是"一个进程"。操作系统通过页表机制,让每个进程都以为自己独占了0-4GB,实际上它们的物理内存是隔离的。
结论:
1.这意味着,无论进程如何调度,我们总能找到操作系统!
问题2:
用户和内核,都在同一个0-4GB的地址空间上了
如果用户,随便拿一个虚拟地址3-4GB,用户不就可以随便访问内核中的代码和数据了吗?
OS为了保护自己,不相信任何人!必须采用系统调用的方式进行访问
所以为了保证这样的概念,引入了用户态和内核态
用户态:以用户身份,只能访问自己的0-3GB
内核态:以内核的身份,运行你通过系统调用的方式,访问OS3-4GB
在系统中,用户或者OS自己,怎么知道当前处于内核态,还是用户态?
在CPU内部有一些寄存器特定位置会记录下是内核态还是用户态
cs寄存器:低两位比特位:0:内核态
3:用户态
CPU内部有标志位记录当前什么态
所以int 0x80 syscall就是转换态
CPL是x86架构中最关键的特权级概念,直接决定了CPU当前执行的代码具有什么权限。
CPL的本质:CS寄存器的低2位
[全局or局部]段描述符表 RPL,DPL
所以在键盘上ctrl+c,键盘ctrl+c后会以硬件中断的方式告诉操作系统,键盘有东西被按下操作系统执行键盘所对应的中断处理方法,从键盘中读取ctrl+c,识别到是一个终止前台任务的处理,所以直接执行我们对应的中断处理方法,就是向目标进程直接发信号,发送的就是当前进程修改task_struct判定表比特位。当把中断处理完,进程继续运行,发生缺陷,陷阱,异常,中断而导致当前进程陷入内核,执行完毕返回进行判定检查,没有block有pending,handler,自定义,所以我们就执行信号处理
CPU内部的软中断,比如int 0x80或者syscall,我们叫做 陷阱
CPU内部的软中断,比如除零/野指针等,我们叫做 异常。
捕捉信号的另一种做法
sigaction
• sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回-1。signo是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体:
• 将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动作,赋值为⼀个函数指针表示用自定义函数捕捉信号,或者说向内核注册了⼀个信号处理函数,该函数返回值为void,可以带⼀个int参数,通过参数可以得知当前信号的编号,这样就可以用同⼀个函数处理多种信号。显然,这也是⼀个回调函数,不是被main函数调用,而是被系统所调用。
NAME
sigaction, rt_sigaction - examine and change a signal action
SYNOPSIS
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
信号编号 如何处理信号 输出型参数---历史上信号带回来,方便恢复 自定义捕捉方法
RETURN VALUE
sigaction() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;---信号集
int sa_flags;
void (*sa_restorer)(void);
};
test.cpp
#include<iostream> #include<unistd.h> #include<signal.h> #include<cstdlib> void handler(int signum) { std::cout<<"hello signal:"<<signum<<std::endl; exit(0); } int main() { struct sigaction act,oact; act.sa_handler = handler; sigaction(SIGINT,&act,&oact);//对2号信号进行了自定义捕捉 while(true) { std::cout<<"hello world"<<std::endl; sleep(1); } return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out hello world hello world hello world ^Chello signal:2当某个信号的处理函数被调用时,内核自动将当前信号加⼊进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产⽣,那么它会被阻塞到当前处理结束为止。如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时⾃动恢复原来的信号屏蔽字。sa_flags字段包含⼀些选项,代码都把sa_flags设为0,sa_sigaction是实时信号的处理函数
当前正在处理的信号,会被自动屏蔽
test.cpp
#include<iostream> #include<unistd.h> #include<signal.h> #include<cstdlib> void handler(int signum) { std::cout<<"hello signal:"<<signum<<std::endl; while(true) { //不断获取pending表! sigset_t pending; sigpending(&pending); for(int i = 31;i>=1;i--) { if(sigismember(&pending,i)) std::cout<<"1"; else std::cout<<"0"; } std::cout<<std::endl; sleep(1); } exit(0); } int main() { struct sigaction act,oact; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT,&act,&oact);//对2号信号进行了自定义捕捉 while(true) { std::cout<<"hello world:"<<getpid()<<std::endl; sleep(1); } return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out hello world:208965 hello world:208965 hello world:208965 hello world:208965 ^Chello signal:2 0000000000000000000000000000000 0000000000000000000000000000000 ^C0000000000000000000000000000010 0000000000000000000000000000010 ^C0000000000000000000000000000010 ^\Quit把其他信号加进来
test.cpp
#include<iostream> #include<unistd.h> #include<signal.h> #include<cstdlib> void handler(int signum) { std::cout<<"hello signal:"<<signum<<std::endl; while(true) { //不断获取pending表! sigset_t pending; sigpending(&pending); for(int i = 31;i>=1;i--) { if(sigismember(&pending,i)) std::cout<<"1"; else std::cout<<"0"; } std::cout<<std::endl; sleep(1); } exit(0); } int main() { struct sigaction act,oact; act.sa_handler = handler; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask,3); sigaddset(&act.sa_mask,4); act.sa_flags = 0; sigaction(SIGINT,&act,&oact);//对2号信号进行了自定义捕捉,对2,3,4都屏蔽 while(true) { std::cout<<"hello world:"<<getpid()<<std::endl; sleep(1); } return 0; }终端1 root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out hello world:209374 hello world:209374 hello world:209374 hello world:209374 hello world:209374 hello world:209374 hello world:209374 hello signal:2 0000000000000000000000000000000 0000000000000000000000000000000 0000000000000000000000000000010 0000000000000000000000000000010 0000000000000000000000000000010 0000000000000000000000000000110 0000000000000000000000000000110 0000000000000000000000000000110 0000000000000000000000000000110 0000000000000000000000000001110 0000000000000000000000000001110 0000000000000000000000000001110 0000000000000000000000000001110 Killed 终端2 root@iZ5waahoxw3q2bZ:~/linux-learning/linux# kill -2 209374 root@iZ5waahoxw3q2bZ:~/linux-learning/linux# kill -2 209374 root@iZ5waahoxw3q2bZ:~/linux-learning/linux# kill -3 209374 root@iZ5waahoxw3q2bZ:~/linux-learning/linux# kill -4 209374 root@iZ5waahoxw3q2bZ:~/linux-learning/linux# kill -9 209374可重入函数
main执行流
handler执行流
insert方法,被两个以上的执行流重复进入了--函数被重入了--不可重入函数/可重入函数
大部分的函数,都是不可重入的!
如果一个函数符合以下条件之一则是不可重入的:
• 调用了malloc或free,因为malloc也是用全局链表来管理堆的。
• 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
函数,只有自己的临时变量---可重入的
volatile c语言关键字
声明易变变量,防止编译器优化
test.cpp
#include<iostream> #include<unistd.h> #include<signal.h> #include<cstdlib> int flag = 0; void handler(int signu) { std::cout<<"更改全局变量,"<<flag<<"-> 1"<<std::endl; flag = 1; } int main() { signal(2,handler); while(!flag); std::cout<<"process quit normal!"<<std::endl; return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out ^C更改全局变量,0-> 1 process quit normal!main里面,并不会对flag进行修改
比如编译器优化级别比较高的情况下
flag->register->优化到寄存器中!
CPU两种运算:算数运算,逻辑运算
1.把变量从内存导入到CPU中
2.在CPU寄存器内进行某种计算
3.如果需要可以写回,不需要反之
但是编译器优化flag->register->优化到寄存器中!
1、2省去1,不再进行缓存直接导入寄存器
gcc编译时可以指定优化级别
man gcc/g++优化级别-O0 -O1 -O2...
默认-O0
root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp -O0 root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out ^C更改全局变量,0-> 1 process quit normal! root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp -O1 root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out ^C更改全局变量,0-> 1 ^C更改全局变量,1-> 1 ^C更改全局变量,1-> 1 ^\Quitctrl+c退出不了,优化太高了
寄存器覆盖了进程看到变量的真实情况,内存不可见了!
所以拿volatile修饰一下
volatile int flag=0;
保证内存空间可见性!
test.cpp
#include<iostream> #include<unistd.h> #include<signal.h> #include<cstdlib> volatile int flag = 0; void handler(int signu) { std::cout<<"更改全局变量,"<<flag<<"-> 1"<<std::endl; flag = 1; } int main() { signal(2,handler); while(!flag); std::cout<<"process quit normal!"<<std::endl; return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp -O1 root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out ^C更改全局变量,0-> 1 process quit normal! root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp -O3 root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out ^C更改全局变量,0-> 1 process quit normal!SIGCHLD信号
17) SIGCHLD
进程讲过用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第⼀种方式,父进程阻塞了就不能处理自己的⼯作了;采用第⼆种方式,父进程在处理自己的工作的同时还要记得时不时地轮询⼀下,程序实现复杂。
其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以⾃定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
请编写⼀个程序完成以下功能:父进程fork出子进程,子进程调用exit(2)终止,父进程自定义SIGCHLD信号的处理函数,在其中调用wait获得子进程的退出状态并打印。
默认动作是:SIGCHLD P1990 Ign Child stopped or terminated
子进程在终止时会给父进程发SIGCHLD信号---默认动作是:Ign
test.cpp
#include<iostream> #include<signal.h> #include<unistd.h> #include<cstdio> #include<sys/wait.h> void Say(int num) { std::cout<<"father get a signal:"<<num<<std::endl; } int main() { //父进程 signal(SIGCHLD,Say);//父进程 pid_t id=fork(); if(id==0) { std::cout<<"I am child,exit"<<std::endl; sleep(3); exit(3); } waitpid(id,nullptr,0); std::cout<<"I am father,exit"<<std::endl; return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out I am child,exit father get a signal:17 I am father,exittest.cpp
#include<iostream> #include<signal.h> #include<unistd.h> #include<cstdio> #include<sys/wait.h> void WaitAll(int num) { while(true) { pid_t n=waitpid(-1,nullptr,WNOHANG);//waitpid默认是阻塞的! //如果子进程被创建很多,可以将所有子进程进行回收 //WNOHANG叫做非阻塞轮询 if(n==0) { break; } else if(n<0) { std::cout<<"waitpid error:"<<std::endl; break; } } std::cout<<"father get a signal:"<<num<<std::endl; } int main() { //父进程 signal(SIGCHLD,WaitAll);//父进程 pid_t id=fork();//如果我们有10个子进程呢?6个退出了,4个没退? if(id==0) { sleep(3); std::cout<<"I am child,exit"<<std::endl; exit(3); } while(true) { std::cout<<"I am father,exit"<<std::endl; sleep(1); } return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out hello I am father,exit I am father,exit I am father,exit I am child,exit I am father,exit waitpid error: father get a signal:17 father get a signI am father,exit I am father,exit I am father,exit I am father,exit I am father,exit ^Croot@iZ5waahoxw3q2bZ:~/linux-learning/linux# while :; do ps ajx | head -1 && ps ajx | grep hello ; sleep 1;done PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211124 211123 207845 pts/1 211123 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211129 211128 207845 pts/1 211128 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 211133 211134 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211138 211137 207845 pts/1 211137 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 211133 211134 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211154 211153 207845 pts/1 211153 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 211133 211134 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211166 211165 207845 pts/1 211165 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211173 211172 207845 pts/1 211172 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211178 211177 207845 pts/1 211177 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211183 211182 207845 pts/1 211182 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211198 211197 207845 pts/1 211197 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211208 211207 207845 pts/1 211207 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211133 211133 208299 pts/0 211133 S+ 0 0:00 ./a.out hello 207845 211213 211212 207845 pts/1 211212 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211219 211218 207845 pts/1 211218 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211236 211235 207845 pts/1 211235 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211253 211252 207845 pts/1 211252 S+ 0 0:00 grep --color=auto hello ^C事实上,由于UNIX的历史原因,要想不产生僵尸进程还有另外⼀种办法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可用。请编写程序验证这样做不会产生僵尸进程。
将SIGCHLD的处理动作置为SIG_IGN
test.cpp
#include <iostream> #include <signal.h> #include <unistd.h> #include <cstdio> #include <sys/wait.h> int main() { // 父进程 signal(SIGCHLD, SIG_IGN);// 父进程 for (int i = 0; i < 10; i++) { pid_t id = fork(); // 如果我们有10个子进程呢?6个退出了,4个没退? if (id == 0) { sleep(3); std::cout << "I am child,exit" << std::endl; exit(3); // if(i<=6) exit(3); // else pause(); } } while (true) { std::cout << "I am father,exit" << std::endl; sleep(1); } return 0; }root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# g++ test.cpp root@iZ5waahoxw3q2bZ:~/linux-learning/linux/26-6-25# ./a.out hello I am father,exit I am father,exit I am father,exit I am child,exit I am child,exit I am child,exit I am child,exit I am child,exit I am child,exit I am child,exit I am child,exit I am child,exit I am child,exit I am father,exit I am father,exit I am father,exit I am father,exit I am father,exit ^Croot@iZ5waahoxw3q2bZ:~/linux-learning/linux# while :; do ps ajx | head -1 && ps ajx | grep hello ; sleep 1;done PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211475 211474 207845 pts/1 211474 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211480 211479 207845 pts/1 211479 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211485 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211486 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211487 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211488 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211489 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211490 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211491 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211492 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211493 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211494 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211498 211497 207845 pts/1 211497 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211485 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211486 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211487 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211488 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211489 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211490 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211491 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211492 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211493 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211494 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211523 211522 207845 pts/1 211522 R+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211485 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211486 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211487 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211488 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211489 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211490 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211491 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211492 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211493 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 211484 211494 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211553 211552 207845 pts/1 211552 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211560 211559 207845 pts/1 211559 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211565 211564 207845 pts/1 211564 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211570 211569 207845 pts/1 211569 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 208299 211484 211484 208299 pts/0 211484 S+ 0 0:00 ./a.out hello 207845 211585 211584 207845 pts/1 211584 S+ 0 0:00 grep --color=auto hello PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 207845 211596 211595 207845 pts/1 211595 S+ 0 0:00 grep --color=auto hello ^Csignal(SIGCHLD,SIG_IGN)忽略处理
不是SIGCHLD默认动作是Ign吗,为什么还要手动设置?
signal(SIGCHLD,SIG_DFL)是默认处理动作
可以认为SIG_DEL缺省动作是Ign
感谢你的观看,期待我们下次再见!