2016-01-10 3 views
1

Я делаю проект для своих исследований в соответствии с рекомендациями, и у меня есть проблема. Я должен сделать связь с использованием сигналов и труб следующим образом:Ошибка отправки сигнала между родительским и дочерним процессами в C

  • процесс 2 приема сигнала и отправить его родителю
  • родительского процесс сохранения значения сигнала в трубе и отправить сигнал для обработки 1 читать трубу
  • процесс 1 чтение трубки и посылает сигнал для обработки 2 читать трубу
  • процесса 2 чтения трубки и посылает сигнал для обработки 3 читать трубу
  • процесса 3 чтения труба

К сожалению, когда я отправляю один из поддерживаемых сигналов (например, г. 20), чтобы обрабатывать 2 сигнала, зацикливаются, и программа прерывается SIGUSR1.

int stopm=0; 
int stop1=0; 
int stop2=0; 
int stop3=0; 
int termm=1; 
int term1=1; 
int term2=1; 
int term3=1; 

void obslugam(int sig){ 
    signal(15,obslugam); 
    signal(18,obslugam); 
    signal(20,obslugam); 

    sigset_t mask_set; 
    sigfillset(&mask_set); 
    sigdelset(&mask_set,SIGUSR1); 
    sigdelset(&mask_set,SIGTERM); 
    sigdelset(&mask_set,SIGCONT); 
    sigdelset(&mask_set,SIGTSTP); 
    sigprocmask(SIG_BLOCK,&mask_set,NULL); 
    printf("Jestem M i odebralem sygnal %d\n",sig); 
    if(sig==15){ 
     write(pm1[1],"15",2); 
     write(pm2[1],"15",2); 
     write(pm3[1],"15",2); 
    } 
    if(sig==18){ 
     write(pm1[1],"18",2); 
     write(pm2[1],"18",2); 
     write(pm3[1],"18",2); 
    } 
    if(sig==20){ 
     write(pm1[1],"20",2); 
     write(pm2[1],"20",2); 
     write(pm3[1],"20",2); 
    } 
    kill(PID1,10); 

} 
void obsluga1(int sig){ 
    signal(10,obsluga1); 

    sigset_t mask_set; 
    sigfillset(&mask_set); 
    sigdelset(&mask_set,SIGUSR1); 
    sigprocmask(SIG_BLOCK,&mask_set,NULL); 
    printf("Jestem 1 i odebralem sygnal %d\n",sig); 
    char bufor_p1[2]={0}; 
    if(read(pm1[0],&bufor_p1,2)==-1)perror("PIPE1\n"); 
    if(strchr(bufor_p1,53)!=NULL) printf("Jestem 1 i dostałem 15\n"); 
    else if(strchr(bufor_p1,56)!=NULL) printf("Jestem 1 i dostałem 18\n"); 
    else if(strchr(bufor_p1,48)!=NULL) printf("Jestem 1 i dostałem 20\n"); 
    kill(PID2,10); 
} 
void obsluga2(int sig){ 
    signal(10,obsluga2); 
    signal(15,obsluga2); 
    signal(18,obsluga2); 
    signal(20,obsluga2); 

    sigset_t mask_set; 
    sigfillset(&mask_set); 
    sigdelset(&mask_set,SIGUSR1); 
    sigdelset(&mask_set,SIGTERM); 
    sigdelset(&mask_set,SIGCONT); 
    sigdelset(&mask_set,SIGTSTP); 
    sigprocmask(SIG_BLOCK,&mask_set,NULL); 
    printf("Jestem 2 i odebralem sygnal %d\n",sig); 
    if(sig==10){ 
     char bufor_p2[2]={0}; 
     if(read(pm2[0],&bufor_p2,2)==-1)perror("PIPE2\n"); 
     if(strchr(bufor_p2,53)!=NULL) printf("Jestem 2 i dostałem 15\n"); 
     else if(strchr(bufor_p2,56)!=NULL) printf("Jestem 2 i dostałem 18\n"); 
     else if(strchr(bufor_p2,48)!=NULL) printf("Jestem 2 i dostałem 20\n"); 
     kill(PID3,10); 
    } 
    else if(sig==15) kill(getppid(),15); 
    else if(sig==18) kill(getppid(),18); 
    else if(sig==20) kill(getppid(),20); 
} 
void obsluga3(int sig){ 
    signal(10,obsluga3); 

    sigset_t mask_set; 
    sigfillset(&mask_set); 
    sigdelset(&mask_set,SIGUSR1); 
    sigprocmask(SIG_BLOCK,&mask_set,NULL); 
    printf("Jestem 3 i odebralem sygnal %d\n",sig); 
    char bufor_p3[2]={0}; 
    if(read(pm3[0],&bufor_p3,2)==-1)perror("PIPE3\n"); 
    if(strchr(bufor_p3,53)!=NULL) printf("Jestem 3 i dostałem 15\n"); 
    else if(strchr(bufor_p3,56)!=NULL) printf("Jestem 3 i dostałem 18\n"); 
    else if(strchr(bufor_p3,48)!=NULL) printf("Jestem 3 i dostałem 20\n"); 
} 

int main(){ 

    (...) 

    pipe(pm1); 
    pipe(pm2); 
    pipe(pm3); 
    signal(15,obslugam); 
    signal(18,obslugam); 
    signal(20,obslugam); 

    if((PID1=fork())==0) { 
     close(pm1[1]); 
     signal(10,obsluga1); 
    } 
    else if((PID2=fork())==0) { 
     close(pm2[1]); 
     signal(10,obsluga2); 
     signal(15,obsluga2); 
     signal(18,obsluga2); 
     signal(20,obsluga2); 
    } 
    else if((PID3=fork())==0){ 
     printf("\nJestem procesem nr 2. Oto moj PID: %d\n\n",PID2); 
     close(pm3[1]); 
     signal(10,obsluga3); 
    } 
    else{ 
     close(pm1[0]); 
     close(pm2[0]); 
     close(pm3[0]); 
    } 

    (...) 

} 

Я стараюсь, но не могу найти место, где я совершил ошибку. Буду признателен за вашу помощь.

+0

Просьба указать [Минимальный полный и проверенный пример] (https://stackoverflow.com/help/mcve). Нет кода '...', пожалуйста. И, пожалуйста, укажите точный результат - неясно, какие именно фразы типа «сигналы зациклированы» означают точно. – kaylum

+0

Вы пытаетесь запутать свой код? Зачем использовать магические числа вместо символьных констант, а не определенные константы для сигналов? – Olaf

ответ

0

Я не могу найти место, где я допустил ошибку.

Ошибка была проигнорирована в содержании первого абзаца на странице справочника signal (2).

Поведение сигнала() варьируется в разных версиях UNIX, а также варьируется исторически в разных версиях Linux. Избегайте использования его : вместо этого используйте sigaction (2). См. «Портативность» ниже.

На странице руководства были описаны различные способы реализации различных Unix-приложений signal(). Он описал первоначальное поведение UNIX, которое также было принято с помощью System V Unix, а именно, что после установки обработчика сигнала через signal(), как только сигнал будет доставлен, сигнал будет сброшен на SIG_DFL.

Страница руководства затем заявляет следующее:

Ситуация на Linux выглядит следующим образом:

  • сигнал() системный вызов Ядро обеспечивает System V семантику.

Выводы:

1) При использовании системных вызовов, как signal(), важно, чтобы прочитать страницу руководства.

2) В первый раз, когда SIGUSR1 вызывает пользовательский обработчик сигналов в Linux, обработчик сигнала сбрасывается на SIG_DFL.

3) Затем, если ничего не происходит, второй раз, когда принимается сигнал, процесс будет прекращен, для сигнала, действие SIG_DFL - это прекращение процесса.

4) Действие SIG_DFL для SIGUSR1 - это прекращение процесса. Поэтому во второй раз, когда ваш процесс получит этот сигнал, он будет прекращен. Это похоже на поведение, которое вы видите.

5) Можно сразу переустанавливать обработчик сигнала, после получения SIGUSR1, конечно, но, как объясняет страничное руководство, ничто не мешает процессу от получения SIGUSR1, прежде чем он имеет возможность повторно установить обработчик сигнала ,

6) По этой причине на странице руководства вам будет вместо этого использоваться sigaction (2).

7) Еще лучше, в Linux, использовать signalfd(2). Это, конечно же, Linux-специфический API.

Кроме того, образец кода имеет по крайней мере две дополнительные ошибки:

char bufor_p2[2]={0}; 
    if(read(pm2[0],&bufor_p2,2)==-1)perror("PIPE2\n"); 
    if(strchr(bufor_p2,53)!=NULL) printf("Jestem 2 i dostałem 15\n"); 

Есть две ошибки здесь. Этот код, кажется, читает два символа из трубы и ожидает, что они будут прочитаны полностью.

Первая ошибка заключается в том, что при чтении более одного байта от трубы или устройства вам не гарантируется, что вы успешно прочитаете количество запрошенных байтов. В этом случае вы можете в итоге прочитать один байт. Когда приложение считывает меньшее количество байтов, чем оно запросило, это обязанность приложения действовать соответственно, как правило, повторите попытку для чтения оставшихся данных.

Есть некоторые гарантии от ядра Linux, что это никогда не произойдет на Linux, но технически это ошибка. То же самое касается записи на трубку или устройство. Другие части показанного кода пытаются записать более одного байта в трубу и предположить, что это будет успешным.

В надежном приложении все попытки чтения или записи из трубы, сокета или некоторых других устройств должны быть готовы к рассмотрению возможности того, чтобы меньшее количество байтов было прочитано или записано, чем запрошено, и повторите попытку.

Вторая ошибка заключается в том, что два байта считываются из канала и помещаются в массив из двух символов, которые затем проверяются с помощью strchr().

Ожидаемые два байта, в соответствии с остальной частью кода, представляют собой две десятичные цифры, обозначающие номер сигнала.

strchr() ожидает нуль завершающую строку. Разумеется, два байта в двухбайтовом массиве символов не будут заканчиваться нулями. Это приведет к неопределенному поведению.

Смежные вопросы