Ошибка в форке и услепе
Я пишу этот код: http://ideone.com/cNypUb
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void signchld (int signal){
fprintf (stderr, "[X] child exited\n");
}
int main(){
signal (SIGCHLD, signchld);
int i;
for(i=0;i<=300;i++){
pid_t f;
f=fork();
if(f==0){
//child
usleep(3*1000000);
fprintf (stderr, "[C1] %d\n",i);
exit(0);
fprintf (stderr, "[C2] %d\n",i);
}else if(f>0){
fprintf (stderr, "[P1] %d\n",i);
usleep(20000000);
fprintf (stderr, "[P2] %d\n",i);
}
}
return 0;
}
но [p2]
запускать каждые 3 секунды, а затем запускать следующий цикл
Я ожидаю увидеть этот вывод:
[P1] 0
[C1] 0
[X] child exited
через 20 секунд
[P2] 0
[P1] 1
[C1] 1
[X] child exited
4 ответа
Это обработчик сигнала signchld()
это прерывает usleep()
в родительском, как мы можем доказать, подставив
usleep(20000000);
с
if (usleep(20000000) < 0) {
if (errno == EINTR)
fprintf (stderr, "[PX] usleep() interrupted by a signal\n");
}
(и, конечно, в том числе errno.h
). Это напечатает
[P1] 0
[C1] 0
[X] child exited
[PX] usleep() interrupted by a signal
[P2] 0
[P1] 1
и так далее.
В моей системе (GNU/Linux) справочная страница для usleep()
гласит:
4.3BSD, POSIX.1-2001. POSIX.1-2001 объявляет эту функцию устаревшей; вместо этого используйте nanosleep(2). POSIX.1-2008 удаляет спецификацию usleep().
SUSv2 и POSIX.1-2001 документируют только возврат ошибок EINVAL.
Функция usleep не может принимать аргументы со значениями больше 1 000 000 usleep(20000000), безусловно, должно вызывать непредсказуемое поведение.
Вы видите, что родительский процесс просыпается раньше, чем через 20 секунд, как вы ожидали, потому что выходящий ребенок доставил сигнал SIGCHLD, который вы зарегистрировали для обработки. Этот сигнал просыпается usleep()
преждевременно. Возвращает -1 и имеет значение errno EINTR.
Проверьте возвращаемое значение usleep()
, Это, конечно, EINTR, как определено на странице руководства: http://linux.die.net/man/3/usleep
Вам нужно добавить wait()
позвоните в ваш обработчик SIGCHLD ( http://linux.die.net/man/2/wait).
Также обратите внимание, что не определено, какой процесс запускается первым после fork()
, Несмотря на то, что они являются родительскими и дочерними, они планируются независимо операционной системой. Также, usleep()
гарантирует время сна не меньше, чем количество переданных ему useconds, если оно не прервано. Это не гарантирует, что процесс пробудится в это время, хотя обычно это будет довольно близко.
Не пытайтесь использовать usleep()
или любой из его вариантов для синхронизации процесса. Используйте правильные процедуры IPC.