2015-06-28 15 views
6

Tôi đang sử dụng hướng dẫn này từ trang web http://www.code2learn.com/2011/01/signal-program-using-parent-child.html và cố gắng hiểu tại sao trẻ không nhận được tín hiệu?gửi tín hiệu từ cha mẹ sang con

đây là mã:

#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 
void sighup(); /* routines child will call upon sigtrap */ 
void sigint(); 
void sigquit(); 
void main() 
{ int pid; 
    /* get child process */ 
    if ((pid = fork()) < 0) { 
     perror("fork"); 
     exit(1); 
    } 
    if (pid == 0) 
    { /* child */ 
     signal(SIGHUP,sighup); /* set function calls */ 
     signal(SIGINT,sigint); 
     signal(SIGQUIT, sigquit); 
     for(;;); /* loop for ever */ 
    } 
    else /* parent */ 
    { /* pid hold id of child */ 
     printf("\nPARENT: sending SIGHUP\n\n"); 
     kill(pid,SIGHUP); 
     sleep(3); /* pause for 3 secs */ 
     printf("\nPARENT: sending SIGINT\n\n"); 
     kill(pid,SIGINT); 
     sleep(3); /* pause for 3 secs */ 
     printf("\nPARENT: sending SIGQUIT\n\n"); 
     kill(pid,SIGQUIT); 
     sleep(3); 
    } 
} 
void sighup() 
{ signal(SIGHUP,sighup); /* reset signal */ 
    printf("CHILD: I have received a SIGHUP\n"); 
} 
void sigint() 
{ signal(SIGINT,sigint); /* reset signal */ 
    printf("CHILD: I have received a SIGINT\n"); 
} 
void sigquit() 
{ printf("My DADDY has Killed me!!!\n"); 
    exit(0); 
} 

đầu ra:

enter image description here

+0

Mọi người có ý tưởng ???? – user3162878

Trả lời

8

Đó là một điều kiện chủng tộc. Mã của bạn giả định rằng đứa trẻ chạy đầu tiên và không được cha mẹ cho trước khi nó cài đặt tất cả các trình xử lý tín hiệu và bắt đầu lặp lại mãi mãi.

Khi không phải như vậy, phụ huynh có thể gửi tín hiệu cho trẻ trước khi trẻ có cơ hội nhận tín hiệu. Do đó, quá trình con bị giết, vì hành động mặc định cho SIGHUP, SIGINTSIGQUIT là để chấm dứt.

Trong trường hợp cụ thể của bạn, bạn sẽ không bao giờ thấy bất kỳ đầu ra nào của trẻ. Điều này có nghĩa là phụ huynh đã gửi SIGHUP cho đứa trẻ và SIGHUP đã được gửi trước khi đứa trẻ thay đổi hành vi mặc định. Vì vậy, đứa trẻ đã bị giết.

Trên thực tế, nếu bạn đã làm một số kiểm tra lỗi trên giá trị trở lại của kill(2) - mà bạn cần - bạn sẽ thấy ESRCH trong các phụ huynh khi cố gắng gửi SIGINTSIGQUIT, bởi vì đứa trẻ đã đi (giả sử không có quá trình khác trong hệ thống đã được bắt đầu và được chỉ định cùng một PID trong thời gian chờ đợi).

Vì vậy, làm cách nào để khắc phục sự cố? Hoặc sử dụng một số hình thức đồng bộ hóa để buộc trẻ chạy đầu tiên và chỉ để cho phụ huynh thực thi sau khi tất cả trình xử lý tín hiệu được cài đặt hoặc thiết lập trình xử lý tín hiệu trước forking và sau đó bỏ đặt chúng trong phụ huynh. Đoạn code dưới đây sử dụng phương pháp sau:

#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <unistd.h> 

void sighup(int); /* routines child will call upon sigtrap */ 
void sigint(int); 
void sigquit(int); 

int main(void) { 

    int pid; 

    signal(SIGHUP,sighup); /* set function calls */ 
    signal(SIGINT,sigint); 
    signal(SIGQUIT, sigquit); 

    /* get child process */ 
    if ((pid = fork()) < 0) { 
     perror("fork"); 
     exit(1); 
    } 

    if (pid == 0) { 

     /* child */ 
     for(;;); /* loop for ever */ 

    } else { 

     signal(SIGHUP, SIG_DFL); 
     signal(SIGINT, SIG_DFL); 
     signal(SIGQUIT, SIG_DFL); 

     /* parent */ 
     /* pid hold id of child */ 
     printf("\nPARENT: sending SIGHUP\n\n"); 
     kill(pid,SIGHUP); 
     sleep(3); /* pause for 3 secs */ 
     printf("\nPARENT: sending SIGINT\n\n"); 
     kill(pid,SIGINT); 
     sleep(3); /* pause for 3 secs */ 
     printf("\nPARENT: sending SIGQUIT\n\n"); 
     kill(pid,SIGQUIT); 
     sleep(3); 
    } 

    return 0; 
} 

void sighup(int signo) { 
    signal(SIGHUP,sighup); /* reset signal */ 
    printf("CHILD: I have received a SIGHUP\n"); 
} 

void sigint(int signo) { 
    signal(SIGINT,sigint); /* reset signal */ 
    printf("CHILD: I have received a SIGINT\n"); 
} 

void sigquit(int signo) { 
    printf("My DADDY has Killed me!!!\n"); 
    exit(0); 
} 

Ngoài ra, bạn không nên sử dụng signal(2): nó là không đáng tin cậy bằng nhiều cách, và ngữ nghĩa chính xác của nó là nền tảng phụ thuộc. Để đảm bảo tính di động tối đa, bạn nên sử dụng sigaction(2). Tham khảo manpages để tìm hiểu thêm. Dưới đây là đoạn mã tương tự sử dụng sigaction(2) thay vì:

#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <unistd.h> 

void sighup(int); /* routines child will call upon sigtrap */ 
void sigint(int); 
void sigquit(int); 

int main(void) { 

    struct sigaction sigact; 
    sigact.sa_flags = 0; 
    sigemptyset(&sigact.sa_mask); 

    sigact.sa_handler = sighup; 
    if (sigaction(SIGHUP, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(1); 
    } 

    sigact.sa_handler = sigint; 
    if (sigaction(SIGINT, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(1); 
    } 

    sigact.sa_handler = sigquit; 
    if (sigaction(SIGQUIT, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(1); 
    } 

    pid_t pid; 
    /* get child process */ 
    if ((pid = fork()) < 0) { 
     perror("fork"); 
     exit(1); 
    } 

    if (pid == 0) { 

     /* child */ 
     for(;;); /* loop for ever */ 

    } else { 

     sigact.sa_handler = SIG_DFL; 
     sigaction(SIGHUP, &sigact, NULL); 
     sigaction(SIGINT, &sigact, NULL); 
     sigaction(SIGQUIT, &sigact, NULL); 

     /* parent */ 
     /* pid hold id of child */ 
     printf("\nPARENT: sending SIGHUP\n\n"); 
     kill(pid,SIGHUP); 
     sleep(3); /* pause for 3 secs */ 
     printf("\nPARENT: sending SIGINT\n\n"); 
     kill(pid,SIGINT); 
     sleep(3); /* pause for 3 secs */ 
     printf("\nPARENT: sending SIGQUIT\n\n"); 
     kill(pid,SIGQUIT); 
     sleep(3); 
    } 

    return 0; 
} 

void sighup(int signo) { 
    signal(SIGHUP,sighup); /* reset signal */ 
    printf("CHILD: I have received a SIGHUP\n"); 
} 

void sigint(int signo) { 
    signal(SIGINT,sigint); /* reset signal */ 
    printf("CHILD: I have received a SIGINT\n"); 
} 

void sigquit(int signo) { 
    printf("My DADDY has Killed me!!!\n"); 
    exit(0); 
} 

Cuối cùng nhưng không kém, điều quan trọng là đề cập rằng bạn nên luôn luôn biên dịch với -Wall. Chương trình của bạn có một số lỗi:

  • Loại trả về main() phải là int.
  • Trình xử lý tín hiệu nhận được số hiệu làm đối số, vui lòng sử dụng nguyên mẫu và khai báo đúng.
  • fork(2) trả về một pid_t, không phải là int, vui lòng sử dụng đúng loại.
  • Bạn cần phải bao gồm unistd.h để lấy nguyên mẫu phù hợp cho fork(2).
  • printf(3) không phải là tín hiệu không đồng bộ an toàn và do đó bạn không nên gọi nó bên trong bộ xử lý tín hiệu. Nó là ok trong chương trình đồ chơi này để xem làm thế nào tín hiệu làm việc cùng nhau, nhưng hãy nhớ rằng bạn không bao giờ nên làm điều đó trong thế giới thực.Để xem danh sách các chức năng an toàn không đồng bộ tín hiệu, cũng như các hành động mặc định cho mỗi tín hiệu, hãy xem man 7 signal.

Lời khuyên: ngừng học hỏi từ trang web đó. Nếu bạn muốn tìm hiểu loại công cụ này, hãy đọc Lập trình nâng cao trong môi trường UNIX. Đi thẳng đến chaper 10 để tìm hiểu lý do tại sao chính xác signal(2) được coi là không đáng tin cậy và lỗi thời. Đó là một cuốn sách lớn, nhưng nó cũng đáng để đầu tư thời gian của bạn vào nó.

+0

Cảm ơn anh trai thực sự đã giúp đỡ. Và tôi sẽ bỏ phiếu cho việc đề xuất Sách hay nếu nó có thể là có thể. – user3162878

+0

Thứ hai sách thay vì trang web (và giải thích chi tiết, bổ sung khác). – msw

Các vấn đề liên quan