问题是在Linux上使用C的fork()按照这个字母顺序创建进程树。
A: B, C, D
-B: E, F
-C: G
--G: I
-D:
目前,通过使用if,我可以通过观察htop中的PID看到abcdeGFi,而不是正确的顺序。
看到C的PID(目前)总是B的PID+1,所以我试着打了个补丁,在分叉B之前先STOP-C,之后CONT-C。
int b = getpid();
kill(b + 1, SIGSTOP);
fork(); /* E created */
if (getpid() == b) {
fork(); /* F created */
}
kill(b + 1, SIGCONT);
这样就得到了正确的顺序,但是,如果C不在B的旁边,就很难看,而且容易出错,有没有一个完美的方法可以按照这个顺序创建进程?
如果我的理解是正确的。
这意味着
信息这个词在这里用得很宽泛。我的意思是某种形式的信息传递。
这里可以有效地使用管道。比如说... R 需要等待 S (发件人)要创建。
有两种情况: R 将进行。
所以,这种方法是 "防崩溃 "的,也就是说,如果出了问题,你不会让进程永远等待。如果你愿意的话,你甚至可以通过让 S 在关闭管道之前发送一个字节。很好。
这只是一个在正确的时间关闭管道手柄的问题。下面是你的目标实现的演示。(它是用Perl写的,但是 pipe
, fork
, waitpid
, sleep
和 close
只是同名C函数的薄包装。只要忽略 $
.)
#!/usr/bin/perl
use strict;
use warnings;
use feature qw( say );
sub fork_child {
my $sub = shift;
my $pid = fork();
if (!$pid) {
if (!eval { $sub->(@_); 1 }) {
warn( eval { "$@" } // "Unknown error" );
exit(($? >> 8) || $! || 255);
}
exit(0);
}
return $pid;
}
sub a {
$0 = "a";
say "$0 is pid $$";
pipe(my $d_created_recver, my $d_created_sender);
pipe(my $f_created_recver, my $f_created_sender);
my $pid_b = fork_child(\&b, $d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender);
my $pid_c = fork_child(\&c, $d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender);
my $pid_d = fork_child(\&d, $d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender);
close($_) for $d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender;
waitpid($pid_b, 0);
waitpid($pid_c, 0);
waitpid($pid_d, 0);
}
sub b {
my ($d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender) = @_;
$0 = "b";
say "$0 is pid $$";
# Not related to B or its descendants.
close($_) for $d_created_sender, $f_created_recver;
# Wait for D to be created.
read($d_created_recver, my $buf, 1);
close($d_created_recver);
my $pid_e = fork_child(\&e, $f_created_sender);
my $pid_f = fork_child(\&f, $f_created_sender);
# Allow G to be created.
close($f_created_sender);
waitpid($pid_e, 0);
waitpid($pid_f, 0);
}
sub c {
my ($d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender) = @_;
$0 = "c";
say "$0 is pid $$";
# Not related to C or its descendants.
close($_) for $d_created_sender, $d_created_recver, $f_created_sender;
# Wait for F to be created.
read($f_created_recver, my $buf, 1);
close($f_created_recver);
my $pid_g = fork_child(\&g);
waitpid($pid_g, 0);
}
sub d {
my ($d_created_recver, $d_created_sender, $f_created_recver, $f_created_sender) = @_;
$0 = "d";
say "$0 is pid $$";
# Not related to D or its descendants.
close($_) for $d_created_recver, $f_created_sender, $f_created_recver;
# Allow E to be created.
close($d_created_sender);
sleep();
}
sub e {
my ($f_created_sender) = @_;
$0 = "e";
say "$0 is pid $$";
# Not related to E process or its decendants.
close($f_created_sender);
sleep();
}
sub f {
my ($f_created_sender) = @_;
$0 = "f";
say "$0 is pid $$";
# Allow G to be created.
close($f_created_sender);
sleep();
}
sub g {
$0 = "g";
say "$0 is pid $$";
my $pid_i = fork_child(\&i);
waitpid($pid_i, 0);
}
sub i {
$0 = "i";
say "$0 is pid $$";
sleep();
}
a();
产出。
我赞同ikegami对所需保持点和信息传输的分析。下面是一个在C语言中使用semaphores的例子(省略错误检查)。
#include <unistd.h>
#include <sys/sem.h>
int main()
{ // Create set of 2 semaphores; Linux initializes the values to 0.
int ss = semget(IPC_PRIVATE, 2, 0600);
pid_t B, C, D, E, F, G, I; // the child processes
if ((B = fork()) == 0)
{ // wait for semaphore number 0 (D)
semop(ss, &(struct sembuf){.sem_num=0, .sem_op=-1}, 1);
if ((E = fork()) == 0) return sleep(9); // E stay for a while
if ((F = fork()) == 0)
{ // C may now start G - unlock semaphore number 1
semop(ss, &(struct sembuf){.sem_num=1, .sem_op=+1}, 1);
return sleep(9); // F stay for a while
}
return sleep(9); // B stay for a while
}
if ((C = fork()) == 0)
{ // wait for semaphore number 1 (F)
semop(ss, &(struct sembuf){.sem_num=1, .sem_op=-1}, 1);
if ((G = fork()) == 0)
{
if ((I = fork()) == 0) return sleep(9); // I stay for a while
return sleep(9); // G stay for a while
}
return sleep(9); // C stay for a while
}
if ((D = fork()) == 0)
{ // B may now start E, F - unlock semaphore number 0
semop(ss, &(struct sembuf){.sem_num=0, .sem_op=+1}, 1);
return sleep(9); // D stay for a while
}
sleep(9); // A stay for a while
semctl(ss, 0, IPC_RMID); // remove the semaphore set
}