UNIX中system函数的实现为啥要阻塞SIGCHLD信号?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UNIX中system函数的实现为啥要阻塞SIGCHLD信号?相关的知识,希望对你有一定的参考价值。

参考技术A 由于system函数的实现基本原理是使用fork函数创建一个子进程,用子进程调用exec函数,之后将子进程运行的内容替换成了目标程序。如果不阻塞SIGCHLD信号,那么如果在调用system函数之前还创建了一个其它的子进程,那么当system函数中fork创建的子进程结束后会给父进程发送SIGCHLD信号,如果此时父进程设置的信号处理方式是捕捉而且在信号处理函数中调用了wait函数,那么system函数就无法根据其函数中创建的子进程返回状态获取相应的返回值。记得有这样的规定,system函数的返回应该是函数中创建子进程的返回状态。所以为了能保证system能够正确获取system函数中创建的子进程返回状态,SIGCHLD信号必须被阻塞。
同样,为了保证system函数不出现其它的一些问题,要求system函数要忽略SIGINT和SIGQUIT信号,如果system函数调用的程序是交互式的,如“ed”,就可能出现一些小问题。本回答被提问者采纳
参考技术B 在 UNIX的system()函数实现过程中,要求在父进程中忽略掉SIGINT和SIGQUIT信号,但是要将SIGCHLD信号阻塞(在子进程中将 SIGINT和SIGQUIT信号设为默认,SIGCHLD信号解锁)。子进程执行完毕后,在父进程中调用waitpid(pid_t, &state, 0)。问题:
1、若父进程已被waitpid阻塞,在子进程返回时,此时在父进程中SIGCHLD被阻塞(BLOCK),父进程收不到SIGCHLD信号,waitpid()函数能否正确返回,收集到子进程的信息?
2、 waitpid若能正确完成,在以后父进程中,将SIGCHLD信号UNBLOCK,用sigprocmask()函数解锁,书上说,在 sigprocmask()函数返回以前,会将以前阻塞的信号发送给进程,父进程是否还能收到SIGCHLD信号?若能收到何必在开始时将SIGCHLD 进程阻塞。

为啥说nodejs是异步非阻塞

参考技术A 阻塞I/O
程序执行过程中必然要进行很多I/O操作,读写文件、输入输出、请求响应等等。I/O操作时最费时的,至少相对于代码来说,在传统的编程模式中,举个例子,你要读一个文件,整个线程都暂停下来,等待文件读完后继续执行。换言之,I/O操作阻塞了代码的执行,极大地降低了程序的效率。

下面是是一个C#读文件的例子:

private string ReadTxtToStr(string filename)

//打开文件,打开期间其他代码停止执行,直到完成打开后继续执行代码。
FileStream fs = File.Open(filename, FileMode.Open);
Console.WriteLine("我被打开文件阻塞了。");
StreamReader sr = new StreamReader(fs);
//读取文件,读取期间其他代码停止执行,直到完成读取后继续执行代码。
string str=sr.ReadToEnd();
Console.WriteLine("我被读取文件阻塞了。");
return str;

在上述代码中,两个Console.WriteLine()虽然会被执行,但是却被无辜地阻塞一段时间。理论上,如果读取这个文件需要10秒,我们就浪费了10秒在I/O等待中(实际程序运行中有很大一部分时间是浪费在I/O等待上的),在码农眼里这可是天文数字。
Having asynchronous I/O is good, because I/O is more expensive than most code and we should be doing something better than just waiting for I/O.
非阻塞I/O
理解了阻塞I/O,非阻塞I/O就好理解。非阻塞I/O是程序执行过程中,I/O操作不会阻塞程序的执行,也就是在I/O操作的同时,继续执行其他代码(这得益于Node的事件循环机制)。在I/O设备效率还远远低于CPU效率的时代,这种I/O模型(非阻塞I/O)为程序带来的性能上的提高是非常可观的。

好,下面感受一下怎么用Node.js实现非阻塞I/O,继续读文件,看码:

var fs = require("fs");
fs.readFile("./testfile", "utf8", function(error, file)
if (error) throw error;
console.log("我读完文件了!");
);
console.log("我不会被阻塞!");
复制上面代码保存为test.js,并在同一目录下新建一个名为testfile的文件,用node命令运行test.js,你将看到以下输出:

我不会被阻塞!

我读完文件了!

这显然不符合传统的程序执行顺序,注意,这就是Node.js的非阻塞I/O了。

首先解释下面程序,如果你熟悉JavaScript,请忽略。

var fs = require("fs");
以上代码:引入Node.js内置的File System文件系统模块fs。require()相当与Java的import,C++的include。

fs.readFile("./testfile", "utf8", function(error, file)
if (error) throw error;
console.log("我读完文件了!");
);
以上代码:进行I/O操作,给readFile绑定一个回调函数function(error,file),并在读取testfile完成后执行回调函数。期间,后面的代码继续执行,不受I/O阻塞。

这就是为什么先看到“我不会被阻塞!”而后看到“我读完文件了!”的缘故。

Node.js事件轮询机制(event loop)
《Node入门》推荐我们去读一下Mixu的一篇关于事件轮询的博文,的确值得一读,我英语一般,开着词典还能勉强看,略懂吧。

Mixu说的最经典的一句话:

Everything runs in parallel except your code!

(在Node中)除了代码,一切都是并行的!

理解这句话,再去学Node,也就事半功倍了!本回答被提问者采纳

以上是关于UNIX中system函数的实现为啥要阻塞SIGCHLD信号?的主要内容,如果未能解决你的问题,请参考以下文章

system函数的总结

10.5 Interrupted System Calls

Unix5种IO模型

verilog中为啥非阻塞赋值要用绝对时延

为啥说nodejs是异步非阻塞

为啥我的 IUnknown 释放函数会阻塞我的子线程?