2011-01-28 36 views
6

Có sự khác biệt nào giữa "danh sách mã 1" và "danh sách mã 2" không? Bởi vì trong Liệt kê Mã 1, quá trình con có thể bắt tín hiệu SIGTERM và thoát ra độc đáo. Nhưng mã listng 2 đang kết thúc đột ngột trên tín hiệu SIGTERM.tín hiệu gọi điện sau ngã ba

Tôi đang sử dụng Linux và C.

Mã 1

if (signal(SIGTERM, stopChild) == SIG_ERR) { 
    printf("Could not attach signal handler\n"); 
    return EXIT_FAILURE; 
} 
pid = fork(); 

Mã 2

pid = fork(); 
if (signal(SIGTERM, stopChild) == SIG_ERR) { 
    printf("Could not attach signal handler\n"); 
    return EXIT_FAILURE; 
} 

Phần lạ là trong Mã 2, cả quá trình con và cha đều đặt trình xử lý tín hiệu cho SIGTERM. Vì vậy, đây là nghĩa vụ phải làm việc. Phải không?

+0

Tôi vừa thử nghiệm nó, hoạt động tốt cho tôi. Cả hai quy trình thoát ra một cách duyên dáng thông qua stopChild() gọi trong cả hai trường hợp. –

+0

Bạn có từng cơ hội gọi fork() từ trong chuỗi không? –

+2

Bạn có thể cung cấp một chương trình ví dụ đầy đủ thể hiện hành vi đó không? – wich

Trả lời

5

Nếu bạn đang gửi SIGTERM từ cha mẹ, kết quả cuối cùng phụ thuộc vào thứ tự mà các quy trình được lên lịch.

Nếu đứa trẻ được lên kế hoạch đầu tiên, mọi thứ hoạt động:

           +---------------+ 
               | pid = fork(); | 
               +-------+-------+ 
        parent        |        child 
          +-----------------------------+-----------------------------+ 
          |               | 
          |         +-------------------------+--------------------------+ 
          |         | if (signal(SIGTERM, stopChild) == SIG_ERR) {  | 
          |         |  printf("Could not attach signal handler\n"); | 
          |         |  return EXIT_FAILURE;       | 
          |         | }             | 
          |         +-------------------------+--------------------------+ 
          |               | 
          .               . 
          .               . 
          .               . 
          |               | 
+-------------------------+--------------------------+        | 
| if (signal(SIGTERM, stopChild) == SIG_ERR) {  |        | 
|  printf("Could not attach signal handler\n"); |        | 
|  return EXIT_FAILURE;       |        | 
| }             |        | 
+-------------------------+--------------------------+        | 
          |               | 
          |               | 
          |               | 
      +-------------+-------------+            | 
      | if (pid > 0) {   |            | 
      |  kill(pid, SIGTERM); |            | 
      | }       |            | 
      +-------------+-------------+            | 
          |               | 
          |               | 
          |               | 

Nhưng nếu paren được lên kế hoạch đầu tiên, đứa trẻ có thể đã không có thời gian để thiết lập xử lý tín hiệu:

           +---------------+ 
               | pid = fork(); | 
               +-------+-------+ 
        parent        |        child 
          +-----------------------------+-----------------------------+ 
          |               | 
+-------------------------+--------------------------+        | 
| if (signal(SIGTERM, stopChild) == SIG_ERR) {  |        | 
|  printf("Could not attach signal handler\n"); |        | 
|  return EXIT_FAILURE;       |        | 
| }             |        | 
+-------------------------+--------------------------+        | 
          |               | 
          |               | 
          |               | 
      +-------------+-------------+            | 
      | if (pid > 0) {   |            | 
      |  kill(pid, SIGTERM); |            | 
      | }       |            | 
      +-------------+-------------+            | 
          |               | 
          .               . 
          .               . 
          .               . 
          |               | 
          |         +-------------------------+--------------------------+ 
          |         | if (signal(SIGTERM, stopChild) == SIG_ERR) {  | 
          |         |  printf("Could not attach signal handler\n"); | 
          |         |  return EXIT_FAILURE;       | 
          |         | }             | 
          |         +-------------------------+--------------------------+ 
          |               | 
          |               | 
          |               | 

này được gọi là điều kiện cuộc đua , bởi vì kết quả cuối cùng phụ thuộc vào người được chạy trước tiên.

+0

Tôi không nghĩ rằng đây là vấn đề vì quá trình cha mẹ đã được đưa ra giấc ngủ 10 giây trước khi nó gửi tín hiệu. Dù sao, tôi chấp nhận điều này như là câu trả lời ngay bây giờ vì tôi không thể tái tạo vấn đề. – Sabya

0

Vâng, theo người đàn ông ngã ba:

Các fork(), fork1(), và forkall() chức năng tạo ra một quá trình mới. Không gian địa chỉ của tiến trình mới (processcess con) là một bản sao chính xác của không gian địa chỉ của quá trình gọi (quá trình cha mẹ). Quá trình con được thừa hưởng các thuộc tính sau từ quá trình cha mẹ:

...

thiết lập xử lý tín hiệu o (có nghĩa là, SIG_DFL, SIG_IGN, SIG_HOLD, địa chỉ chức năng)

Trong ví dụ đầu tiên bộ xử lý tín hiệu sẽ được sao chép từ ngữ cảnh của phụ huynh sang đứa trẻ được chia đôi. Nhưng tôi không thể giải thích tại sao trong ví dụ thứ hai thiết lập xử lý tín hiệu trong đứa trẻ sẽ thất bại.

+1

Nhưng trong tín hiệu ví dụ thứ hai() được gọi cho cả hai quy trình. Vì vậy, nó nên thiết lập xử lý tín hiệu cho quá trình con là tốt, phải không? –

+0

@Sergey, chính xác đó là nghi ngờ của tôi! – Sabya

+0

POSIX nói rằng bất kỳ tín hiệu _pending_ nào cho cha/mẹ không được gửi tới con, nó bắt đầu bằng một bộ tín hiệu được khởi tạo bằng không. Nhưng, đứa trẻ _should_ kế thừa các trình xử lý. Gọi fork() trong một thread trong trường hợp không có pthread_atfork() có thể giải thích những gì OP đang gặp phải, tuy nhiên. –

3

Đầu tiên, tín hiệu() không được dùng nữa, tốt hơn nên sử dụng sigaction(). Tôi không nghĩ rằng fork() có nguy cơ biến mất hoàn toàn vì rất nhiều thứ sử dụng nó, nhưng sigaction() cung cấp một giao diện đẹp hơn nhiều.

Hành vi bạn đang gặp phải thường xảy ra do gọi fork() từ trong chuỗi. POSIX xử lý địa chỉ này specifically:

Quy trình phải được tạo với một sợi đơn . Nếu một quá trình đa luồng gọi fork(), quy trình mới phải chứa bản sao của số gọi và toàn bộ không gian địa chỉ, có thể bao gồm các trạng thái của mutexes và các tài nguyên khác. Do đó, để tránh lỗi, quy trình con chỉ có thể thực hiện hoạt động không đồng bộ-tín hiệu an toàn cho đến thời gian như một trong các chức năng exec được gọi. [THR] Bộ xử lý ngã ba có thể được thiết lập bằng phương tiện của hàm pthread_atfork() để duy trì các bất biến ứng dụng trên các cuộc gọi số fork().

Khi các cuộc gọi ứng dụng fork() từ một xử lý tín hiệu và bất cứ ngã ba xử lý đăng ký bởi pthread_atfork() gọi một hàm không asynch tín hiệu an toàn, hành vi là undefined.

Điều này có nghĩa, chứ không phải kế thừa một bản sao của toàn bộ không gian địa chỉ của phụ huynh, bạn thừa hưởng chỉ là một bản sao của gọi đề không gian địa chỉ, mà không chứa bộ xử lý của bạn. Nó có thể được hình dung rằng bạn đang có, thực sự (có lẽ thậm chí vô tình) gọi fork() từ bên trong một sợi.

Quy trình con sẽ nhận được bản sao carbon của không gian địa chỉ của cha mẹ. Sự khác biệt duy nhất với tín hiệu sẽ là đang chờ xử lý tín hiệu, mà trẻ sẽ không nhận được vì nó nhận được bộ tín hiệu được khởi tạo về 0. Nhưng có, nó có được một bản sao của các trình xử lý.

+0

tín hiệu gọi trước khi ngã ba thực sự là thành công, do đó, tín hiệu dispositions làm được sao chép cho trẻ, gọi nó sau khi ngã ba là trường hợp phá vỡ, tức là bằng cách nào đó gọi tín hiệu trong trẻ em không hoạt động. – wich

+0

@wich - đó là lý do tại sao tôi rất nghi ngờ rằng fork() đang được gọi trong chuỗi. –

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