问题描述
pid_t pid;
pid = fork(); //Two processes are made
const char* ptr = secondlinecopy;
if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
{
int status;
if (waitpid(pid,&status,0) == pid && WIFEXITED(status))
{
printf("Exitstatus [");
for (int i = 0; i < noOfTokens; i++)
{
printf("%s ",commands[i]);
}
printf("\b] = %d\n",WEXITSTATUS(status));
}
}
else if (pid == 0) //Child process. Executes commands and prints error if something unexpected happened
{
printf("why does this only print when an invalid command is supplied?");
if (runBGflag==1) insertElement(getpid(),ptr);
execvp(commands[0],commands);
printf ("exec: %s\n",strerror(errno));
exit(1);
}
在代码摘录中,我们看到通过 fork() 创建进程。当 execvp 被提供一个真正的命令时,例如“ls”,我们得到了输出。
/home/kali/CLionProjects/clash/cmake-build-debug: ls
clash CMakeCache.txt cmake_install.cmake Testing
clash.cbp CMakeFiles Makefile
Exitstatus [ls] = 0
但是,如果我们提供无效的命令,输出将是:
/home/kali/CLionProjects/clash/cmake-build-debug: sd
why does this only print when an invalid command is supplied?exec: No such file or directory
Exitstatus [sd] = 1
为什么会这样?进程不应该总是先调用 printf("Why does ...") 然后运行 exec 吗?
解决方法
为什么会这样?进程不应该总是先调用 printf("Why does ...") 然后运行 exec 吗?
假设它是这样工作的:
printf(...) --> internal buffer --(fflush? newline? max_buffer_size?)--> output
通常 stdout
是行缓冲的,而您的 printf
没有换行符。要打印的数据存储在一些内部缓冲区中。当 exec
-ing stdout
未被 fflush
ed 并且父进程被子进程替换为整体时 - 所以所有存储在父进程中的数据,包括一些内部stdout
状态,被删除。当 exec
失败时,stdout
会在您 printf(...\n"
时刷新(或在 exit()
被块缓冲时调用 stdout
后)并显示数据。研究:工作室缓冲模式and setvbuf()
function。
为什么会这样?进程不应该总是先调用 printf("Why does ...") 然后运行 exec 吗?
是的,它应该,而且您没有提出任何理由认为它没有。
printf
将输出定向到标准输出流,当它连接到交互式设备时默认为行缓冲,或块缓冲 否则。当 execvp()
成功时,它将整个程序映像替换为新程序的映像,包括任何 I/O 缓冲区的内容。任何已缓冲但未刷新到底层设备的数据都将丢失。
当 execvp()
失败并且程序随后正常终止时(无论其退出状态如何),所有当时缓冲的缓冲数据都会自动刷新到相关的输出设备。
如果您将换行符附加到正在打印的消息中,或者在 fflush(stdout)
和 printf
调用之间调用 execvp
,或者打印到 { {1}} 而不是 stderr
,或者如果您关闭 stdout
的缓冲。