c++信號處理


signal 函數的使用方法簡單,但並不屬於 POSIX 標准,在各類 UNIX 平台上的實現不盡相同,因此其用途受 到了一定的限制。而 POSIX 標准定義的信號處理接口是 sigaction 函數。

signal函數每次設置具體的信號處理函數(非SIG_IGN)只能生效一次,每次在進程響應處理信號時,隨即將信號處理函數恢復為默認處理方式.所以如果想多次相同方式處理某個信號,通常的做法是,在響應函數開始,再次調用signal設置。

1 int sig_int()
2 {
3     signal(SIGINT, sig_int);
4     ....
5 }

這種代碼段的一個問題是:在信號發生之后到信號處理程序中調用s i g n a l函數之間有一個 時間窗口。在此段時間中,可能發生另一次中斷信號。第二個信號會造成執行默認動作,而對 中斷信號則是終止該進程。這種類型的程序段在大多數情況下會正常工作,使得我們認為它們 正確,而實際上卻並不是如此。 另一個問題是:在進程不希望某種信號發生時,它不能關閉該信號。

sigaction:

1.在信號處理程序被調用時,系統建立的新信號屏蔽字會自動包括正被遞送的信號。因此保證了在處理一個 給定的信號時,如果這種信號再次發生,那么它會被阻塞到對前一個信號的處理結束為止

2.響應函數設置后就一直有效,不會重置

http://man7.org/linux/man-pages/man2/sigaction.2.html

1 struct sigaction {
2    void     (*sa_handler)(int);
3    void     (*sa_sigaction)(int, siginfo_t *, void *);
4    sigset_t   sa_mask;
5    int        sa_flags;
6    void     (*sa_restorer)(void);
7 };

When the SA_SIGINFO flag is specified in act.sa_flags, the signal handler address is passed via the act.sa_sigaction field. This handler takes three arguments, as follows:

1 void handler(int sig, siginfo_t *info, void *ucontext)
2 {
3    ...
4 }

And the signal action (thru sa_sigaction field should do something (machine specific) with its siginfo_t to skip the offending machine instruction, or to mmap the offending address, or call siglongjmp, otherwise when returning from the signal handler you'll get the SIGSEGV again since the offending machine instruction is restarted.

When your signal handler returns (assuming it doesn't call exit or longjmp or something that prevents it from actually returning), the code will continue at the point the signal occurred, reexecuting the same instruction. Since at this point, the memory protection has not been changed, it will just throw the signal again, and you'll be back in your signal handler in an infinite loop.

https://stackoverflow.com/questions/2663456/how-to-write-a-signal-handler-to-catch-sigsegv

這是第一個問題,需要處理完之后,要么退出程序,要么就是進行錯誤處理之后需要跳過當前的代碼。

At the time of generation, a determination shall be made whether the signal has been generated for the process or for a specific thread within the process. Signals which are generated by some action attributable to a particular thread, such as a hardware fault, shall be generated for the thread that caused the signal to be generated. Signals that are generated in association with a process ID or process group ID or an asynchronous event, such as terminal activity, shall be generated for the process.

The problematic aspect of trying to handle SIGSEGV in a multi-threaded program is that, while delivery and signal mask are thread-local, the signal disposition (i.e. what handler to call) is process-global. In other words, sigaction sets a signal handler for the whole process, not just the calling thread. This means that multiple threads each trying to setup their own SIGSEGV handlers will clobber each other's settings.

https://stackoverflow.com/questions/16204271/about-catching-the-sigsegv-in-multithreaded-environment

另一個問題,信號 的mask和delivery是thread local的,但是signal disposition不是。

SIGSEGV is catchable but the behavior after doing so is undefined unless the signal was generated by raise() or kill(). It sounds like you are trying to cover up bugs in your program -- the better solution is to find and squash these bugs so that you're not getting SIGSEGV in the first place. If the thread is executing code which is out of your direct control, you really should be running it in a separate process anyway.

The fundamental problem is that signals behave strangely under pthreads. Signals are not delivered to the thread which triggered them. Instead, they are delivered to whichever thread has the signal unblocked. If all threads have the signal unblocked, then any thread at all could receive the signal, not just the one which triggered it. In other words, pthread_self() may not be referring to the thread which caused the SIGSEGV.

There is no solution to this. In order to ensure that only the faulting thread receives the signal, it must be the only thread with this signal unblocked. But there is no way to accomplish that, because you do not know ahead of time which thread is about to segfault.

The best you can do is to block SIGSEGV in ALL threads but one, and when this thread receives the signal, simply shut everything down gracefully.

https://cboard.cprogramming.com/linux-programming/108364-question-about-pthreads-sigsegv.html

最好的方式還是直接退出。比如如果是寫錯內存,那么繼續執行的話,可能會導致其他線程的結果也是錯的。盡管此時程序並沒有退出。

 http://www.apuebook.com/threadsig.html

apue上的例子,只是打印了哪個線程捕獲了信號,並不能保證,捕獲了信號的線程就是引起信號的線程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM