2012-07-26 49 views
87

Trong Linux, điều gì sẽ xảy ra khi một chương trình (có thể có nhiều luồng) nhận tín hiệu, như SIGTERM hoặc SIGHUP?Xử lý tín hiệu với nhiều luồng trong Linux

Chuỗi nào chặn tín hiệu? Có thể nhiều luồng có cùng tín hiệu không? Có một sợi đặc biệt chuyên dụng hoàn toàn để xử lý tín hiệu? Nếu không, những gì xảy ra bên trong thread đó là để xử lý tín hiệu? Làm thế nào để thực hiện tiếp tục sau khi xử lý tín hiệu thường xuyên kết thúc?

Trả lời

30

Điều này hơi sắc thái, dựa trên phiên bản hạt nhân Linux bạn đang sử dụng.

Giả sử 2.6 chuỗi posix và nếu bạn đang nói về hệ điều hành gửi SIGTERM hoặc SIGHUP, tín hiệu sẽ được gửi để xử lý, được nhận và xử lý bởi chuỗi gốc. Sử dụng các chủ đề POSIX, bạn cũng có thể gửi SIGTERM tới từng chủ đề riêng lẻ, nhưng tôi nghi ngờ bạn đang hỏi về những gì xảy ra khi hệ điều hành gửi tín hiệu đến tiến trình.

Trong phiên bản 2.6, SIGTERM sẽ khiến các chuỗi con xuất hiện "sạch", trong đó 2,4, các chuỗi con bị bỏ lại ở trạng thái không xác định.

+0

Và những gì xảy ra bên trong sợi rễ khi một tín hiệu nhận được? Hãy nói rằng tôi đã viết một xử lý tín hiệu tùy chỉnh cho SIGUSR1, và bây giờ tôi đang gửi tín hiệu đó cho quá trình. Chủ đề gốc sẽ nhận được tín hiệu đó. Có lẽ nó đang ở giữa một số chức năng tại thời điểm đó. Chuyện gì đang xảy ra vậy? –

+1

nếu bạn có thiết lập trình xử lý, nó sẽ được coi là gián đoạn và luồng chương trình sẽ tạm dừng và trình xử lý tùy chỉnh của bạn sẽ được thực thi. Một khi nó được thực hiện, điều khiển sẽ trở lại, giả sử bạn đã không làm bất cứ điều gì để thay đổi dòng chảy bình thường (thoát ra vv). – Alan

+0

Lưu ý rằng điều này là dành riêng cho SIGUSR1, mà IIRC không làm gián đoạn các cuộc gọi hệ thống. Nếu bạn đã thử điều này với SIGINT chẳng hạn, nó có thể làm gián đoạn luồng đọc và khi bạn quay lại đọc, luồng có thể trả lại lỗi bị gián đoạn. – Alan

102

pthreads(7) mô tả rằng POSIX.1 yêu cầu tất cả chủ đề trong một quá trình cổ phần thuộc tính, bao gồm:

  • khuynh hướng tín hiệu

POSIX.1 cũng đòi hỏi một số thuộc tính được biệt cho mỗi thread , bao gồm:

  • mặt nạ tín hiệu ())

  • thay thế tín hiệu ngăn xếp (complete_signal() thói quen sigaltstack(2))

Linux kernel đã khối mã sau - những ý kiến ​​khá hữu ích:

/* 
    * Now find a thread we can wake up to take the signal off the queue. 
    * 
    * If the main thread wants the signal, it gets first crack. 
    * Probably the least surprising to the average bear. 
    */ 
    if (wants_signal(sig, p)) 
      t = p; 
    else if (!group || thread_group_empty(p)) 
      /* 
      * There is just one thread and it does not need to be woken. 
      * It will dequeue unblocked signals before it runs again. 
      */ 
      return; 
    else { 
      /* 
      * Otherwise try to find a suitable thread. 
      */ 
      t = signal->curr_target; 
      while (!wants_signal(sig, t)) { 
        t = next_thread(t); 
        if (t == signal->curr_target) 
          /* 
          * No thread needs to be woken. 
          * Any eligible threads will see 
          * the signal in the queue soon. 
          */ 
          return; 
      } 
      signal->curr_target = t; 
    } 

    /* 
    * Found a killable thread. If the signal will be fatal, 
    * then start taking the whole group down immediately. 
    */ 
    if (sig_fatal(p, sig) && 
     !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && 
     !sigismember(&t->real_blocked, sig) && 
     (sig == SIGKILL || !t->ptrace)) { 
      /* 
      * This signal will be fatal to the whole group. 
      */ 

Vì vậy, bạn thấy rằng bạn chịu trách nhiệm về nơi tín hiệu được phân phối:

Nếu quy trình đã đặt bố cục của tín hiệu thành SIG_IGN hoặc SIG_DFL, sau đó tín hiệu bị bỏ qua (hoặc mặc định - giết, lõi hoặc bỏ qua) cho tất cả các chuỗi.

Nếu quy trình của bạn đã đặt bố cục tín hiệu thành một trình xử lý cụ thể, bạn có thể kiểm soát luồng nào sẽ nhận tín hiệu bằng cách thao tác các mặt nạ tín hiệu chủ đề cụ thể bằng cách sử dụng pthread_sigmask(3). Bạn có thể chỉ định một luồng để quản lý tất cả hoặc tạo một chuỗi cho mỗi tín hiệu hoặc bất kỳ hỗn hợp nào của các tùy chọn này cho các tín hiệu cụ thể hoặc bạn dựa vào hành vi mặc định hiện tại của hạt nhân Linux để phân phối tín hiệu cho chuỗi chính.

Một số tín hiệu, tuy nhiên, là đặc biệt:

A signal may be generated (and thus pending) for a process as 
    a whole (e.g., when sent using kill(2)) or for a specific 
    thread (e.g., certain signals, such as SIGSEGV and SIGFPE, 
    generated as a consequence of executing a specific machine- 
    language instruction are thread directed, as are signals 
    targeted at a specific thread using pthread_kill(3)). A 
    process-directed signal may be delivered to any one of the 
    threads that does not currently have the signal blocked. If 
    more than one of the threads has the signal unblocked, then 
    the kernel chooses an arbitrary thread to which to deliver 
    the signal. 
+6

Cảm ơn bạn đã trải qua những rắc rối khi trích đoạn mã hạt nhân! rất hữu ích. – cheshirekow

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