How to Handle Signals in Multithreaded Linux Programs (C Example)
This article explains the differences between threads and processes in Linux, introduces the concept of POSIX signals, describes how signals are delivered and handled in multithreaded programs, and provides a complete C example demonstrating proper signal handling across threads.
Difference Between Threads and Processes
In Linux a thread shares the address space and most resources of its parent process, resulting in lower context‑switch overhead and higher concurrency than separate processes.
Concept of Signals
Signals are a POSIX inter‑process communication mechanism used to notify a process that an event has occurred. Each signal has a unique identifier (e.g., SIGINT, SIGTERM) and can be sent to a process or to specific threads.
Relationship Between Threads and Signals
Signal delivery
Signals are delivered to the process; the kernel then selects one of the process’s threads—typically arbitrarily—to handle the signal. Any thread in a multithreaded program may receive the signal.
Signal handling
Each thread can install its own handler using signal or sigaction. When the selected thread receives the signal, the registered handler runs in that thread’s context.
Signal propagation and masks
By default a signal is visible to all threads, but a thread can block specific signals with pthread_sigmask or set a per‑thread mask, allowing fine‑grained control.
Example
The program below creates two threads, installs a process‑wide handler for SIGINT, and ignores SIGINT in the worker threads. When SIGINT (Ctrl‑C) is sent, the handler runs in the thread chosen by the kernel.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread %lu started.
", (unsigned long)pthread_self());
/* Ignore SIGINT in this thread */
signal(SIGINT, SIG_IGN);
while (1) {
sleep(1);
}
return NULL;
}
void signal_handler(int signum) {
printf("Signal %d received in thread %lu.
", signum, (unsigned long)pthread_self());
}
int main(void) {
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread_function, NULL);
pthread_create(&tid2, NULL, thread_function, NULL);
/* Register process‑wide handler */
signal(SIGINT, signal_handler);
/* Keep the main thread alive */
while (1) {
sleep(1);
}
return 0;
}Key points
Signals are sent to a process, not directly to a thread.
The kernel arbitrarily selects a thread to deliver the signal.
Handlers run in the context of the receiving thread.
Use pthread_sigmask or sigprocmask to block signals in threads that should not handle them.
Properly managing masks and handlers is essential for robust multithreaded applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
