上下文就是这个Redis问题.我们有一个wait3()
等待AOF重写子项在磁盘上创建新AOF版本的调用.当孩子完成后,通知父母wait3()
以便用新的AOF替换旧的AOF.
但是,在上述问题的上下文中,用户向我们通知了一个错误.我修改了一点Redis 3.0的实现,以便在wait3()
返回-1 时清楚地记录,而不是因为这种意外情况而崩溃.所以这就是显而易见的事情:
wait3()
当有待等待的孩子时,我们会打电话.SIGCHLD
应设置为SIG_DFL
,没有代码Redis的所有设置这个信号,所以它的默认行为.wait3()
按预期成功运行.wait3()
开始返回-1.AFAIK在我们调用的当前代码中wait3()
是不可能的,因为当没有挂起的子节点时,因为当创建AOF子节点时,我们设置server.aof_child_pid
为pid的值,并且我们仅在成功wait3()
调用之后重置它.
所以wait3()
应该没有理由失败-1 ECHILD
,但它确实如此,所以可能僵尸孩子不是出于某种意想不到的原因而创建的.
假设1:在某些奇怪的条件下Linux可能会丢弃僵尸孩子,例如因为内存压力?看起来不合理,因为僵尸只附加了元数据但谁知道.
请注意,我们打电话wait3()
给WNOHANG
.并且鉴于默认情况下SIGCHLD
设置为SIG_DFL
,唯一应该导致失败并返回-1的条件,并且ECHLD
应该没有可用于报告信息的僵尸.
假设2:可能发生的其他事情但是没有解释,如果它发生,是在第一个孩子死后,SIGCHLD
处理程序被设置为SIG_IGN
,导致wait3()
返回-1和ECHLD
.
假设3:有没有办法从外部移除僵尸儿童?也许这个用户有某种脚本可以在后台删除僵尸进程,以便信息不再可用wait3()
?据我所知,如果父母不等待它(使用或处理信号)并且如果没有被忽略,则永远不可能移除僵尸,但也许有一些特定于Linux的方式.waitpid
SIGCHLD
假设4:实际上有在Redis的代码一些bug,使我们成功wait3()
的孩子第一次不正确复位状态,后来我们叫wait3()
连连,但不再有僵尸,所以它返回-1.分析代码看起来不可能,但也许我错了.
另一件重要的事情:我们过去从未见过这一点.这显然只发生在这个特定的Linux系统中.
更新:Yossi Gottlieb提出 …
我知道这waitpid()
用于等待一个过程完成,但是如何才能完全使用它?
在这里我想做的是,创造两个孩子并等待第一个孩子完成,然后在退出前杀死第二个孩子.
//Create two children
pid_t child1;
pid_t child2;
child1 = fork();
//wait for child1 to finish, then kill child2
waitpid() ... child1 {
kill(child2) }
Run Code Online (Sandbox Code Playgroud) 我有点困惑.据我了解,waitpid的pid为-1意味着我等待所有孩子完成但是如果我在WNOHANG的waitpid中添加一个选项,那么这些选项如果没有完成就会立即退出......这些似乎非常令人困惑.
为什么我要告诉计算机等待子进程完成然后立即告诉它如果没有孩子完成就立即退出?
有人可以解释这个选项和WUNTRACED选项吗?我不知道被追查的意义.
我正在尝试从子进程返回一个整数值.
但是,如果我使用exit(1)我得到256作为输出.exit(-1)给出65280.
有没有办法可以获得我从子进程发送的实际int值?
if(!(pid=fork()))
{
exit(1);
}
waitpid(pid,&status,0);
printf("%d",status);
Run Code Online (Sandbox Code Playgroud)
编辑:使用exit(-1)(这是我真正想要的)我得到255作为WEXITSTATUS(状态)的输出.它应该是未签名的吗?
我有一个产生一组孩子的脚本.家长必须等待每个孩子完成.
我的脚本执行类似于以下perl脚本:
#! /usr/bin/perl
use strict;
use warnings;
print "I am the only process.\n";
my @children_pids;
for my $count (1..10){
my $child_pid = fork();
if ($child_pid) { # If I have a child PID, then I must be the parent
push @children_pids, $child_pid;
}
else { # I am the child
my $wait_time = int(rand(30));
sleep $wait_time;
my $localtime = localtime;
print "Child: Some child exited at $localtime\n";
exit 0; # Exit the child
}
}
foreach my $child (@children_pids) …
Run Code Online (Sandbox Code Playgroud) 我有一个程序生成一个随机数n,然后循环n次.
在每次迭代中,它随机化值的值sleeptime
,并调用fork.子进程休眠sleeptime
几秒钟,然后使用索引变量的值退出.
然后父进程再次循环,等待每个进程终止.当每个进程终止时,我正在尝试注销进程的pid和childid,但这就是我遇到麻烦的地方.pids按顺序打印,childid保持为0.
我究竟做错了什么?
int main(int argc, char* argv[])
{
// Wire up the timer
long time = elapsedTime(0);
/* Generate a random number between MINFORKS and MAXFORKS
*/
unsigned int seed = generateSeed(0);
int n = rand_r(&seed) % MAXFORKS + MINFORKS-1;
/* Log next step
*/
time = elapsedTime(1);
printf("%li: Number of forks = %i\n", time, n);
/* Hang on to the PIDs so we can wait for them after forking
*/
pid_t *PIDs = …
Run Code Online (Sandbox Code Playgroud) 在下面的脚本中,我试图弄清楚waitpid
它是如何工作的,但它不会等待ssh
进程退出.done
是立即打印,而不是在该ssh
过程存在之后.
题
waitpid
当我给它的pid退出时,我怎么才继续?
#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;
use POSIX ":sys_wait_h";
my $pm = Parallel::ForkManager->new(5);
my $pid = $pm->start;
my $p = $pid;
if (!$pid) {
system("ssh 10.10.47.47 sleep 10");
$pm->finish;
}
$p = qx(/usr/bin/pgrep -P $p);
print "ssh pid is $p\n";
my $kid;
do {
$kid = waitpid($p, 0);
} while $kid > 0;
print "done\n";
Run Code Online (Sandbox Code Playgroud)
我也试过了
while (1) {
$p = kill 0, $p;
print "x";
sleep …
Run Code Online (Sandbox Code Playgroud) 我想弄清楚发送SIGCHLD信号的进程的pid是什么,我想在我为SIGCHLD创建的信号处理程序中这样做.我该怎么做?我尝试着:
int pid = waitpid(-1, NULL, WNOHANG);
Run Code Online (Sandbox Code Playgroud)
因为我想等待产生的任何子进程.
如果我fork
是子进程,并且子进程在父进程调用之前退出waitpid
,那么设置的退出状态信息是否waitpid
仍然有效?如果是的话,什么时候变得无效; 即,如何确保我可以调用waitpid
子pid并在任意时间后继续获取有效的退出状态信息,以及如何"清理"(告诉操作系统我不再对退出感兴趣完成的子进程的状态信息)?
我正在玩下面的代码,似乎退出状态信息在孩子完成后至少几秒钟有效,但我不知道多长时间或如何通知操作系统我不会waitpid
再次打电话:
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "Failed to fork\n");
return EXIT_FAILURE;
}
else if (pid == 0) { // code for child process
_exit(17);
}
else { // code for parent
sleep(3);
int status;
waitpid(pid, &status, 0);
waitpid(pid, &status, 0); // call `waitpid` again just to see if …
Run Code Online (Sandbox Code Playgroud) 如果在命令末尾找到"&",我试图模仿后台运行进程的bash功能.我有以下功能......我不认为它正在做我想做的事情
int execute(char* args[],int background,int *cstatus){
pid_t child;
pid_t ch; /*Pid of child returned by wait*/
if ((child = fork()) == 0){ /*Child Process*/
execvp(args[0],args);
fprintf(stderr, "RSI: %s: command not found\n",args[0]); /*If execvp failes*/
exit(1);
}else{ /*Parent process*/
if (child== (pid_t)(-1)) {
fprintf(stderr,"Fork failed\n"); exit(1);
}else{
if (background==0){ /*If not running in background..wait for process to finish*/
ch = wait(cstatus);
}else{
printf("%ld Started\n",(long)getpid());
/* printf("Parent: Child %ld exited with status = %ld\n", (long) ch, (long)cstatus);
*/ }}
}
return 0; …
Run Code Online (Sandbox Code Playgroud)