在Linux程式設計中,我們經常使用 Fork()
。然而不少情況下,fork
是有危險的。但是又不能簡單使用vfork
替換就成了。這個筆記說明了兩者使用的一些注意點。
本文地址:https://segmentfault.com/a/11...
Reference:
fork與vfork的區別
vfork,fork,exec函式的區別
C語言函式 atexit execl execlp ……(太長了)
vfork() 與 fork()
pid_t vfork(void);
vfork的作用
函式vfork
的作用是建立一個子程式,而這個子程式的作用是用於呼叫exec()
,從而再執行一個新程式(往往是用來執行其它的程式)
程式碼空間
在程式的執行效果上,fork
會將父程式的地址空間複製一份,,但是vfork
並不是這麼做,而是 vfork 之後的子程式,在呼叫 exec 或 exit 之前,在父程式的空間中執行。
執行順序
vfork
保證子程式優先執行到exec
或exit
之前,父程式都不會被排程。fork
父子程式執行順序不確定。
因此,執行了vfork
之後,子程式請立即執行 exec,而不要再執行一次 fork,否則就可能導致死鎖。
或者這麼說,如果在exec
或exit
之前依賴於父程式的進一步動作,就會導致死鎖
另外請留意,exec
並不是建立程式,只是用新程式替換了當前程式的上下文。
system()的替代
頻繁呼叫system()
之後,有可能卡死不返回,就是因為出現了這個情況。system
是基於fork
實現的,呼叫後父子程式呼叫順序不一定,可能導致system()
呼叫死鎖。
這個危險的函式,現在我們已經禁用了。換成使用vfork
或者是__libc_fork
實現,程式碼如下(這份是我自己寫的,不是公司的程式碼,不過原理上差不多):
#define _CMD_LEN (256)
static int _system (char *cmd);
int AMCSystemCmd (const char *format, ...)
{
char cmdBuff[_CMD_LEN];
va_list vaList;
va_start (vaList, format);
vsnprintf ((char *)cmdBuff, sizeof(cmdBuff), format, vaList);
va_end (vaList);
return _system ((char *)cmdBuff);
}
extern int __libc_fork (void);
static int _system (char *command)
{
int pid = 0;
int status = 0;
char *argv[4];
extern char **environ;
if (NULL == command) {
return -1;
}
pid = __libc_fork(); /* vfork() also works */
if (pid < 0) {
return -1;
}
if (0 == pid) { /* child process */
_close_all_fds(); /* 這是我自己寫的一個函式,用來關閉所有繼承的檔案描述符。可不用 */
argv[0] = "sh";
argv[1] = "-c";
argv[2] = command;
argv[3] = NULL;
execve ("/bin/sh", argv, environ); /* execve() also an implementation of exec() */
exit (127);
}
// else
/* wait for child process to start */
do
{
if (waitpid (pid, &status, 0) < 0) {
if (errno != EINTR) {
return -1;
}
else {
return status;
}
}
} while (1);
return 0;
}
使用時用AMCSystemCmd()
直接替代system
即可,還支援動態引數列表呢