您可以將信號發送到使用pthread_kill()
特定線程,或者如果你不介意被GNU專用,使用pthread_sigqueue()
(可以指定一個int
或void *
處理程序可以通過info->si_value
訪問)。
每個信號只有一個信號處理程序。這意味着一個特定的信號將總是調用相同的處理函數,而不管它發生在哪個線程中。如果一個線程設置了新的信號處理程序,則信號處理程序將針對所有線程更改。
但是,解決方法很簡單:使用每線程函數指針來定義信號處理程序應該調用哪個函數。請記住信號處理程序的限制 - 您只能在信號處理程序中使用async-signal safe functions。
/* Simplify by defining the signal handler function type, assume SA_SIGINFO */
typedef void (*signal_handler_t)(int, siginfo_t *, void *);
/* Per-thread variable pointing to the desired function */
static __thread signal_handler_t thread_handler = NULL;
/* Process-wide actual signal handler */
static void signal_handler(int signum, siginfo_t *info, void *context)
{
signal_handler_t func;
func = __sync_fetch_and_or(&thread_handler, (signal_handler_t)0);
if (func)
func(signum, info, context);
}
原子負載(__sync_fetch_and_or()
),可以使用一個簡單的原子商店在任何時間點,甚至沒有阻塞信號平凡改變每個線程處理器。切換到功能new_thread_handler
然後
signal_handler_t func;
do {
func = thread_handler;
} while (!__sync_bool_compare_and_swap(&thread_handler, func, new_thread_handler));
的__sync_fetch_and_or()
和功能開關既可以通過一個C++ 11式__atomic_
調用所替換,但我沒有GCC最近還不夠,所以我仍然使用舊式__sync_
來電。
POSIX還支持實時信號,SIGRTMIN+0
,SIGRTMIN+1
,..,SIGRTMAX
。他們還有額外的好處,即他們中的一個以上可以同時待決。它們比傳統信號更適合這種事物。
信號並不是那麼棒。在Linux上,您可以使用eventfds進行通信,並讓每個線程在其各自的fd上運行一個'epoll'循環。這對於負載均衡也很有用,因爲您可以有多個線程等待* same * eventfd,並且確保* one *被保證喚醒。 –
@KerrekSB這實際上是一個非常好的解決方案,如果你不挖掘不可移植性。偉大的發現! –