Có thể bỏ qua tín hiệu (mất)?


9

Tôi có một ứng dụng đang liên lạc với công nhân thông qua các tín hiệu (SIGUSR1 / SIGUSR2 / SIGSTOP).

Tôi có thể tin tưởng rằng bất cứ điều gì xảy ra, mọi tín hiệu sẽ được xử lý và xử lý bởi trình xử lý không?

Điều gì xảy ra nếu tín hiệu được gửi nhanh hơn không thể ứng dụng xử lý chúng (ví dụ: do tải máy chủ cao tại thời điểm này)?

Câu trả lời:


8

Ngoài vấn đề "quá nhiều tín hiệu", các tín hiệu có thể bị bỏ qua một cách rõ ràng. Từ man 2 signal:

If the signal signum is delivered to the process, then one of the
following happens:    
  *  If the disposition is set to SIG_IGN, then the signal is ignored.

Tín hiệu cũng có thể bị chặn. Từ man 7 signal;

A signal may be blocked, which means that it will not be delivered
until it is later unblocked.  Between the time when it is generated
and when it is delivered a signal is said to be pending.

Cả hai tập hợp tín hiệu bị chặn và bị bỏ qua đều được kế thừa bởi các tiến trình con, do đó, có thể xảy ra quá trình cha mẹ của ứng dụng của bạn đã bỏ qua hoặc chặn một trong các tín hiệu này.

Điều gì xảy ra khi nhiều tín hiệu được phát trước khi quá trình xử lý xong các tín hiệu trước đó? Điều đó phụ thuộc vào hệ điều hành. Các signal(2)trang được liên kết ở trên thảo luận về nó:

  • Hệ thống V sẽ đặt lại bố trí tín hiệu về mặc định. Tệ hơn, việc cung cấp nhanh chóng nhiều tín hiệu sẽ dẫn đến các cuộc gọi đệ quy (?).
  • BSD sẽ tự động chặn tín hiệu cho đến khi xử lý xong.
  • Trên Linux, điều này phụ thuộc vào các cờ biên dịch được đặt cho GNU libc, nhưng tôi mong đợi hành vi BSD.

4
Trang người dùng của Linux cho signal(2)gợi ý rõ ràng rằng bạn tránh sự nhầm lẫn này bằng cách sử dụng sigaction(2)thay thế.
Nate Eldredge

7

Bạn không thể tin tưởng rằng mọi tín hiệu được gửi sẽ được gửi đi. Ví dụ, nhân linux "kết hợp" SIGCHLD nếu một quá trình mất nhiều thời gian để xử lý SIGCHLD từ một tiến trình con đã thoát.

Để trả lời một phần câu hỏi khác của bạn, các tín hiệu sẽ được "xếp hàng" bên trong kernel nếu một số tín hiệu khác nhau đến quá ngắn trong một khoảng.

Bạn nên sử dụng sigaction()để thiết lập trình xử lý tín hiệu với sa_sigactionthành viên của siginfo_t, thiết lập sa_maskthành viên của siginfo_tđối số một cách cẩn thận. Tôi nghĩ rằng điều này có nghĩa là che giấu tất cả các tín hiệu "asynch" ít nhất. Theo trang hướng dẫn dành cho Linux sigaction(), bạn cũng sẽ che giấu tín hiệu đang được xử lý. Tôi nghĩ bạn nên đặt sa_flagsthành viên thành SA_SIGINFO, nhưng tôi không thể nhớ tại sao tôi lại có sự mê tín này. Tôi tin rằng điều này sẽ giúp quá trình của bạn trở thành một trình xử lý tín hiệu luôn được thiết lập mà không có điều kiện cuộc đua và một điều kiện không bị gián đoạn bởi hầu hết các tín hiệu khác.

Viết chức năng xử lý tín hiệu của bạn rất, rất cẩn thận. Về cơ bản chỉ cần đặt một biến toàn cục để chỉ ra rằng tín hiệu đã bị bắt và phần còn lại của quá trình xử lý hành động mong muốn cho tín hiệu đó. Tín hiệu sẽ được che dấu trong khoảng thời gian ít nhất theo cách đó.

Ngoài ra, bạn sẽ muốn kiểm tra mã xử lý tín hiệu của mình thật kỹ. Đặt nó trong một quy trình thử nghiệm nhỏ và gửi càng nhiều tín hiệu SIGUSR1 và SIGUSR2 càng tốt, có thể từ 2 hoặc 3 chương trình gửi tín hiệu cho mục đích đặc biệt. Trộn lẫn trong một số tín hiệu khác, sau khi bạn tin rằng mã của bạn có thể xử lý SIGUSR1 và SIGUSR2 nhanh chóng và chính xác. Chuẩn bị tinh thần cho việc gỡ lỗi khó khăn.

Nếu bạn đang sử dụng linux và chỉ linux, bạn có thể nghĩ về việc sử dụng signalfd()để tạo một mô tả tệp mà bạn có thể select()hoặc thăm dò để nhận các tín hiệu đó. Sử dụng signalfd()có thể làm cho việc gỡ lỗi dễ dàng hơn.


2
Không chỉ SIGCLD bị kết hợp: tất cả các tín hiệu có khả năng kết hợp lại nếu chúng được phân phối trước khi chúng có thể được xử lý.
Gilles 'SO- ngừng trở nên xấu xa'

Có biện pháp nào về thời gian "quá dài" đối với tín hiệu SIGCHLD không? Tôi đang gặp phải hành vi này trong chương trình của mình ngay bây giờ và trình xử lý tín hiệu của tôi không mất hơn ~ 100ms tôi sẽ nghĩ.
xrisk

@Rishav - theo hiểu biết của tôi, không có cách nào để tìm hiểu "quá dài" là gì. Tôi hy vọng rằng tải hệ thống tổng thể là quan trọng. Đó là, những gì các quá trình khác và hạt nhân đang làm sẽ ảnh hưởng đến "thời gian" giữa các tín hiệu để chúng được kết hợp. Không phải là một câu trả lời hữu ích, tôi nghĩ.
Bruce Ediger

6

Một tín hiệu được đảm bảo được phát, theo nghĩa là nếu một quá trình gọi thành công kill, sau đó mục tiêu sẽ nhận được tín hiệu. Điều này không đồng bộ: người gửi không có cách nào để biết khi nào tín hiệu được nhận hoặc xử lý. Tuy nhiên, điều này không đảm bảo rằng tín hiệu sẽ được phát. Mục tiêu có thể chết trước khi nó có thể xử lý tín hiệu. Nếu mục tiêu đang bỏ qua tín hiệu tại thời điểm nó được phát, tín hiệu sẽ không có hiệu lực. Nếu mục tiêu nhận được nhiều trường hợp của cùng một số tín hiệu trước khi có thể xử lý chúng, các tín hiệu có thể (và thường là) được hợp nhất: nếu bạn gửi cùng một tín hiệu hai lần đến một quy trình, bạn không thể biết liệu quy trình có nhận được tín hiệu không một hoặc hai lần. Tín hiệu chủ yếu được thiết kế để giết một quá trình hoặc như một cách để làm cho quá trình chú ý, chúng không được thiết kế để liên lạc như vậy.

Nếu bạn cần giao hàng đáng tin cậy thì bạn cần một cơ chế giao tiếp khác. Có hai cơ chế giao tiếp chính giữa các quy trình: một đường ống cho phép giao tiếp đơn hướng; một ổ cắm cho phép giao tiếp hai chiều và nhiều kết nối đến cùng một máy chủ. Nếu bạn cần mục tiêu để xử lý nhiều thông báo như bạn gửi, hãy gửi byte qua một đường ống.


4
Ý của bạn là viết "Tín hiệu được đảm bảo được phát" kể từ khi bạn tiếp tục mô tả một số cách mà tín hiệu sẽ không được gửi (tức là quá trình đã chết trước khi nhận được hoặc tín hiệu được kết hợp lại)?
Johnny

2

Hạt nhân có thể tự do kết hợp các tín hiệu tiêu chuẩn nếu có nhiều tín hiệu được phân phối trong khi bị chặn. Mặt khác, tín hiệu thời gian thực không bị khuyết tật tương tự.

Từ trang hướng dẫn tín hiệu (7) :

Tín hiệu thời gian thực được phân biệt bằng cách sau:

  1. Nhiều trường hợp tín hiệu thời gian thực có thể được xếp hàng. Ngược lại, nếu nhiều phiên bản của tín hiệu tiêu chuẩn được phát trong khi tín hiệu đó hiện đang bị chặn, thì chỉ có một phiên bản được xếp hàng.

Hãy thử sử dụng tín hiệu có số trong phạm vi SIGRTMIN đến SIGRTMAX.


Có giới hạn cho tín hiệu thời gian thực, nhưng nó khá cao. Một tín hiệu sẽ bị loại bỏ nếu số lượng tín hiệu đang chờ xử lý chưa được gửi bởi người dùng vượt quá RLIMIT_SIGPENDING. ulimit -ihiển thị giá trị này là 63432 trên Ubuntu 18.04.
Bain
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.