Each thread has its own signal shielding word, but the signal processing is shared by all threads in the process.
This means that although a single thread can block some signals, when the thread modifies the processing behavior related to a certain signal, all threads must share the change of the processing behavior.
In this way, if a signal is ignored, and other threads can restore the default processing behavior of the signal, or set a new processing program for the signal, the signal selection of the above thread can be revoked.
The signal in the process is sent to a single thread. If the signal is related to hardware failure or timer timeout, the signal is sent to the thread that causes the event, other signals are sent to any thread.
The behavior of sigprocmask is not defined in multi-threaded processes. The thread must use pthread_sigmask.
IntPthread_sigmask (
IntHow,
ConstSigset_t
* Newmask, sigset_t
* Oldmask); // return value: if it succeeds, 0 is returned; otherwise, an error number is returned.
The pthread_sigmask function is basically the same as the sigprocmask function. Besides pthread_sigmask working in the thread, the error code is returned when the task fails, instead of setting errno and returning-1 as in sigprocmask.
The thread can wait for one or more signals to occur by calling sigwait:
IntSigwait (
ConstSigset_t
* Set,
Int
* Signop); // return value: if it succeeds, 0 is returned. Otherwise, the error number set parameter indicates the signal set waiting for the thread. The integer indicated by signop is returned as the return value, indicates the number of the sent signal (that is, the SIGINT corresponds to the second ).
Note: The signal in the signal set that the sigwait function is waiting for must be blocked before (that is, the waiting signal must be added to the signal shielding word ).
The sigwait function will block the thread that calls it until it receives the signal it is waiting for, and then sigwait will remove it from the never-determined Queue (because it is blocked, it must be pending ), however, it is worth noting that it never determines the status of the acquired signal that is blocked (that is, the original signal shielding word will not change) after the queue is taken out ).
It does only two jobs:
- Wait for the signal it is waiting;
- If the waiting signal is generated, it is removed from the queue.
If multiple threads call sigwait and wait for the same signal, thread blocking occurs. When a signal is delivered, only one thread can return data from sigwait. If the signal is captured (for example, the process creates a signal processing program by using sigaction) and the thread is waiting for the same signal in the sigwait call, then, the operating system determines how the signal is delivered. In this case, the operating system can enable sigwait to return or activate the signal processing program, but neither of them is allowed. (The verification result is as follows: In ubuntu 10.04, sigwait has a higher priority)
To send a signal to a process, you can call kill. To send a signal to a thread, you can call pthread_kill:
#
Include
<Signal. h>
IntPthread_kill (pthread_t thread,
IntSigno); // return value: if it succeeds, 0 is returned; otherwise, an error number is returned. Thread does not exist: esrch signal is invalid: einval
You can pass a 0-value signo to check whether the thread exists. If the default processing action of the signal is to terminate the process, passing the signal to a thread will still kill the whole process. Therefore, we use signal 0, which is a reserved signal, one function is to determine whether a thread is still alive.
The thread in which kill () sends a signal to the process to process the signal is unknown. It may occur that the process itself shields the signal, and a thread does not shield the signal, and the thread then processes the signal.
Note that the alarm timer is a process resource and all threads share the same alarm. Therefore, multiple threads in the process cannot use the alarm timer without interference (or mutual cooperation.
Sample Code:
#
Include
<Stdio. h>
#
Include
<Pthread. h>
#
Include
<Unistd. h>
#
Include
<Stdlib. h>
#
Include
<Signal. h>
VoidSig_thread_func (IntSIG)
{
Printf ("sig_thread_func: Sig = % d \ n", sig );
}VoidSig_func (IntSIG)
{
Printf ("sig_func: Sig = % d \ n", sig );
}
Void
* Func1 (Void
* Arg)
{
Signal (SIGUSR1, sig_thread_func); // thread 1 runs first and sets Signal
Sigset_t set;
Sigfillset (& set );
Sigdelset (& set, SIGUSR1 );
Pthread_sigmask (sig_setmask, & set, null); // thread 1 shields all signals except SIGUSR1
Printf ("pthread 1 run \ n ");
IntI;
For(I
= 0; I <
7; ++ I)
{
Printf ("1... \ n ");
Sleep (1 );
}
Return
0;
}Void
* Func2 (Void
* Arg)
{
Printf ("pthread 2 run \ n ");
IntI;
For(I
= 0; I <
7; ++ I)
{
Printf ("2... \ n ");
Sleep (1 );
}
Return
0;
}
IntMain ()
{
Pthread_t tid1, tid2;
Pthread_create (& tid1, null, func1, null );
Pthread_create (& tid2, null, func2, null );
Sleep (1 );
Signal (SIGUSR1, sig_func); // overwrite the signal set in thread 1
// Send SIGUSR1, sigusr2 to thread 1
Sleep (1 );
Pthread_kill (tid1, SIGUSR1); // call Handler
Sleep (1 );
Pthread_kill (tid1, sigusr2); // blocked, no response
// Send SIGUSR1, sigusr2 to thread 2
Sleep (1 );
Pthread_kill (tid2, SIGUSR1); // call Handler
Sleep (1 );
// Pthread_kill (tid2, sigusr2); // The process is terminated. It is a process!
Sigset_t set;
Sigfillset (& set );
Sigprocmask (sig_setmask, & set, null); // The process shields all signals.
Sleep (1 );
Kill (getpid (), SIGUSR1); // mobilize handler? Actually, it is thread 1's response.
Pthread_join (tid1, null );
Pthread_join (tid2, null );
Return
0;
}
Running result:
HuangCheng @ Ubuntu :~ $./A. Out
Pthread 2 run
2...
Pthread 1 run
1...
2...
1...
2...
Sig_func: Sig =
10
1...
2...
1...
Sig_func: Sig =
10
2...
1...
2...
1...
2...
Sig_func: Sig =
10
1...
Sample Code 2:
#
Include<Stdio. h>
#
Include<Pthread. h>
#
Include<Signal. h>
Static
VoidSig_alrm (IntSigno );
Static
VoidSig_init (IntSigno );
Int
Main ()
{
Sigset_t set;
IntSIG; sigemptyset (& set );
Sigaddset (& set, sigalrm );
Pthread_sigmask (sig_setmask, & set, null); // block the sigalrm Signal
Signal (sigalrm, sig_alrm );
Signal (SIGINT, sig_init); sigwait (& set,
& Sig); // sigwait only deletes the signal from the queue and does not change the signal mask. That is, when the sigwait function returns, the signal it listens to is still blocked.
Switch(SIG ){
Case
14:
Printf ("sigwait, receive signal sigalrm \ n ");
/* Do the job when catch the sigwait */
Break;
Default:
Break;
}
// Sigdelset (& set, sigalrm );
// Pthread_sigmask (sig_setmask, & set, null );
For(;;)
{}
Return
0;
}
Static
Void
Sig_alrm (IntSigno)
{
Printf ("after sigwait, catch sigalrm \ n ");
Fflush (stdout );
Return;
}
Static
Void
Sig_init (IntSigno)
{
Printf ("catch SIGINT \ n ");
Return;
}
Run the following command:
First terminal:
HuangCheng @ Ubuntu :~ $./A. Out
The second terminal:
HuangCheng @ Ubuntu :~ $ Kill-2 2682
HuangCheng @ Ubuntu :~ $ Kill-2 2682
HuangCheng @ Ubuntu :~ $ Kill-14 2682
HuangCheng @ Ubuntu :~ $ Kill-14 2682
HuangCheng @ Ubuntu :~ $ Kill-14 2682
HuangCheng @ Ubuntu :~ $ Kill-14 2682 execution result: HuangCheng @ Ubuntu :~ $./A. Out
Catch SIGINT
Catch SIGINT
Sigwait, receive signal sigalrm
Result Description: sigwait does not change the blocking word, but simply deletes the waiting signal from the queue.
Sample Code 3:
#
Include<Stdio. h>
#
Include<Pthread. h>
#
Include<Signal. h>
Static
VoidSig_alrm (IntSigno );
Static
VoidSig_init (IntSigno );
Int
Main ()
{
Sigset_t set;
IntSIG;
Sigemptyset (& set );
Sigaddset (& set, sigalrm );
Pthread_sigmask (sig_setmask, & set, null); // block the sigalrm Signal
Signal (sigalrm, sig_alrm );
Signal (SIGINT, sig_init );
Sigwait (& set,
& Sig); // sigwait only deletes the signal from the queue and does not change the signal mask. That is, when the sigwait function returns, the signal it listens to is still blocked.
Switch(SIG ){
Case
14:
Printf ("sigwait, receive signal sigalrm \ n ");
/* Do the job when catch the sigwait */
Break;
Default:
Break;
}
Sigdelset (& set, sigalrm );
Pthread_sigmask (sig_setmask, & set, null );
For(;;)
{}
Return
0;
}
Static
Void
Sig_alrm (IntSigno)
{
Printf ("after sigwait, catch sigalrm \ n ");
Fflush (stdout );
Return;
}
Static
Void
Sig_init (IntSigno)
{
Printf ("catch SIGINT \ n ");
Return;
}
Run the following command:
First terminal:
HuangCheng @ Ubuntu :~ $./A. Out
The second terminal:
HuangCheng @ Ubuntu :~ $ Kill-2 2704
HuangCheng @ Ubuntu :~ $ Kill-2 2704
HuangCheng @ Ubuntu :~ $ Kill-2 2704
HuangCheng @ Ubuntu :~ $ Kill-14 2704
HuangCheng @ Ubuntu :~ $ Kill-14 2704
HuangCheng @ Ubuntu :~ $ Kill-14 2704
HuangCheng @ Ubuntu :~ $ Kill-14 2704
Execution result:
HuangCheng @ Ubuntu :~ $./A. Out
Catch SIGINT
Catch SIGINT
Catch SIGINT
Sigwait, receive signal sigalrm
After sigwait, catch sigalrm
After sigwait, catch sigalrm
After sigwait, catch sigalrm
Result Description: If we register a signal processing function and use sigwait to wait for the signal at the same time, who will get the signal? After the experiment, sigwait has a high priority on Ubuntu 10.04.