signal handler and multithreading
I know that signal is a way of communication between CPU and OS kernel. A signal can interrupt the sequence of instructions, execute the handler and go back to the sequence of instructions.
Here is a piece of description of this link:
When a signal that is being caught is handled by a process, the normal
sequence of instructions being executed by the process is temporarily
interrupted by the signal handler. The process then continues
executing, but the instructions in the signal handler are now
executed. If the signal handler returns, the process continues
executing the normal sequence of instructions it was executing when
the signal was caught.
Here is my test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
while(1)
{
cout<<"main"<<endl;
sleep(2);
}
return 0;
}
I execute it and if I press ctrl+C, int will be printed and then I have to wait for 5 seconds, no matter how many times ctrl+C I pressed while waiting for the 5 seconds, nothing happened.
Then I make another test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
thread t1((){while(1){cout<<"t1"<<endl; sleep(2);}});
thread t2((){while(1){cout<<"t2"<<endl; sleep(2);}});
t1.join();
t2.join();
return 0;
}
For this code, I found that I could press ctrl+C three times continually and three int would be printed, then I have to wait for about 5 seconds.
So it seems that the first ctrl+C interrupts the t1 thread, the second interrupts the t2 thread and the third interrupts the main thread.
So signal only interrupt thread instead of the whole process if there are multi-threading?
c++ c linux multithreading signals
|
show 1 more comment
I know that signal is a way of communication between CPU and OS kernel. A signal can interrupt the sequence of instructions, execute the handler and go back to the sequence of instructions.
Here is a piece of description of this link:
When a signal that is being caught is handled by a process, the normal
sequence of instructions being executed by the process is temporarily
interrupted by the signal handler. The process then continues
executing, but the instructions in the signal handler are now
executed. If the signal handler returns, the process continues
executing the normal sequence of instructions it was executing when
the signal was caught.
Here is my test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
while(1)
{
cout<<"main"<<endl;
sleep(2);
}
return 0;
}
I execute it and if I press ctrl+C, int will be printed and then I have to wait for 5 seconds, no matter how many times ctrl+C I pressed while waiting for the 5 seconds, nothing happened.
Then I make another test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
thread t1((){while(1){cout<<"t1"<<endl; sleep(2);}});
thread t2((){while(1){cout<<"t2"<<endl; sleep(2);}});
t1.join();
t2.join();
return 0;
}
For this code, I found that I could press ctrl+C three times continually and three int would be printed, then I have to wait for about 5 seconds.
So it seems that the first ctrl+C interrupts the t1 thread, the second interrupts the t2 thread and the third interrupts the main thread.
So signal only interrupt thread instead of the whole process if there are multi-threading?
c++ c linux multithreading signals
3
Your code invokes undefined behavior. Per footnote 183 of the C standard: "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows the calling of async-signal-safe functions from within a signal handler. Usingcoutand callingsleep()are not async-signal-safe.
– Andrew Henle
Dec 19 '18 at 11:29
1
You don't want to have to handle signals that way. Not ever.
– curiousguy
Dec 19 '18 at 11:43
1
man7.org/linux/man-pages/man7/signal.7.html
– Oliv
Dec 19 '18 at 11:59
@AndrewHenle Yes, you are right. But I need to print something to debug, so I think I have no choice. Using non-reentrant functions in signal handler can be undefined behavior. At least for the code above, it works as expected.
– Yves
Dec 20 '18 at 1:16
1
@Yves On a POSIX system:write( STDOUT_FILENO, buffer, strlen( buffer ) );OrSTDERR_FILENO, if you prefer. Build a C-style string, then usewrite().
– Andrew Henle
Dec 20 '18 at 10:33
|
show 1 more comment
I know that signal is a way of communication between CPU and OS kernel. A signal can interrupt the sequence of instructions, execute the handler and go back to the sequence of instructions.
Here is a piece of description of this link:
When a signal that is being caught is handled by a process, the normal
sequence of instructions being executed by the process is temporarily
interrupted by the signal handler. The process then continues
executing, but the instructions in the signal handler are now
executed. If the signal handler returns, the process continues
executing the normal sequence of instructions it was executing when
the signal was caught.
Here is my test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
while(1)
{
cout<<"main"<<endl;
sleep(2);
}
return 0;
}
I execute it and if I press ctrl+C, int will be printed and then I have to wait for 5 seconds, no matter how many times ctrl+C I pressed while waiting for the 5 seconds, nothing happened.
Then I make another test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
thread t1((){while(1){cout<<"t1"<<endl; sleep(2);}});
thread t2((){while(1){cout<<"t2"<<endl; sleep(2);}});
t1.join();
t2.join();
return 0;
}
For this code, I found that I could press ctrl+C three times continually and three int would be printed, then I have to wait for about 5 seconds.
So it seems that the first ctrl+C interrupts the t1 thread, the second interrupts the t2 thread and the third interrupts the main thread.
So signal only interrupt thread instead of the whole process if there are multi-threading?
c++ c linux multithreading signals
I know that signal is a way of communication between CPU and OS kernel. A signal can interrupt the sequence of instructions, execute the handler and go back to the sequence of instructions.
Here is a piece of description of this link:
When a signal that is being caught is handled by a process, the normal
sequence of instructions being executed by the process is temporarily
interrupted by the signal handler. The process then continues
executing, but the instructions in the signal handler are now
executed. If the signal handler returns, the process continues
executing the normal sequence of instructions it was executing when
the signal was caught.
Here is my test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
while(1)
{
cout<<"main"<<endl;
sleep(2);
}
return 0;
}
I execute it and if I press ctrl+C, int will be printed and then I have to wait for 5 seconds, no matter how many times ctrl+C I pressed while waiting for the 5 seconds, nothing happened.
Then I make another test:
void func(int p)
{
cout<<"int"<<endl;
sleep(5);
}
int main()
{
signal(SIGINT, func);
thread t1((){while(1){cout<<"t1"<<endl; sleep(2);}});
thread t2((){while(1){cout<<"t2"<<endl; sleep(2);}});
t1.join();
t2.join();
return 0;
}
For this code, I found that I could press ctrl+C three times continually and three int would be printed, then I have to wait for about 5 seconds.
So it seems that the first ctrl+C interrupts the t1 thread, the second interrupts the t2 thread and the third interrupts the main thread.
So signal only interrupt thread instead of the whole process if there are multi-threading?
c++ c linux multithreading signals
c++ c linux multithreading signals
asked Dec 19 '18 at 11:22
YvesYves
2,77432363
2,77432363
3
Your code invokes undefined behavior. Per footnote 183 of the C standard: "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows the calling of async-signal-safe functions from within a signal handler. Usingcoutand callingsleep()are not async-signal-safe.
– Andrew Henle
Dec 19 '18 at 11:29
1
You don't want to have to handle signals that way. Not ever.
– curiousguy
Dec 19 '18 at 11:43
1
man7.org/linux/man-pages/man7/signal.7.html
– Oliv
Dec 19 '18 at 11:59
@AndrewHenle Yes, you are right. But I need to print something to debug, so I think I have no choice. Using non-reentrant functions in signal handler can be undefined behavior. At least for the code above, it works as expected.
– Yves
Dec 20 '18 at 1:16
1
@Yves On a POSIX system:write( STDOUT_FILENO, buffer, strlen( buffer ) );OrSTDERR_FILENO, if you prefer. Build a C-style string, then usewrite().
– Andrew Henle
Dec 20 '18 at 10:33
|
show 1 more comment
3
Your code invokes undefined behavior. Per footnote 183 of the C standard: "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows the calling of async-signal-safe functions from within a signal handler. Usingcoutand callingsleep()are not async-signal-safe.
– Andrew Henle
Dec 19 '18 at 11:29
1
You don't want to have to handle signals that way. Not ever.
– curiousguy
Dec 19 '18 at 11:43
1
man7.org/linux/man-pages/man7/signal.7.html
– Oliv
Dec 19 '18 at 11:59
@AndrewHenle Yes, you are right. But I need to print something to debug, so I think I have no choice. Using non-reentrant functions in signal handler can be undefined behavior. At least for the code above, it works as expected.
– Yves
Dec 20 '18 at 1:16
1
@Yves On a POSIX system:write( STDOUT_FILENO, buffer, strlen( buffer ) );OrSTDERR_FILENO, if you prefer. Build a C-style string, then usewrite().
– Andrew Henle
Dec 20 '18 at 10:33
3
3
Your code invokes undefined behavior. Per footnote 183 of the C standard: "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows the calling of async-signal-safe functions from within a signal handler. Using
cout and calling sleep() are not async-signal-safe.– Andrew Henle
Dec 19 '18 at 11:29
Your code invokes undefined behavior. Per footnote 183 of the C standard: "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows the calling of async-signal-safe functions from within a signal handler. Using
cout and calling sleep() are not async-signal-safe.– Andrew Henle
Dec 19 '18 at 11:29
1
1
You don't want to have to handle signals that way. Not ever.
– curiousguy
Dec 19 '18 at 11:43
You don't want to have to handle signals that way. Not ever.
– curiousguy
Dec 19 '18 at 11:43
1
1
man7.org/linux/man-pages/man7/signal.7.html
– Oliv
Dec 19 '18 at 11:59
man7.org/linux/man-pages/man7/signal.7.html
– Oliv
Dec 19 '18 at 11:59
@AndrewHenle Yes, you are right. But I need to print something to debug, so I think I have no choice. Using non-reentrant functions in signal handler can be undefined behavior. At least for the code above, it works as expected.
– Yves
Dec 20 '18 at 1:16
@AndrewHenle Yes, you are right. But I need to print something to debug, so I think I have no choice. Using non-reentrant functions in signal handler can be undefined behavior. At least for the code above, it works as expected.
– Yves
Dec 20 '18 at 1:16
1
1
@Yves On a POSIX system:
write( STDOUT_FILENO, buffer, strlen( buffer ) ); Or STDERR_FILENO, if you prefer. Build a C-style string, then use write().– Andrew Henle
Dec 20 '18 at 10:33
@Yves On a POSIX system:
write( STDOUT_FILENO, buffer, strlen( buffer ) ); Or STDERR_FILENO, if you prefer. Build a C-style string, then use write().– Andrew Henle
Dec 20 '18 at 10:33
|
show 1 more comment
3 Answers
3
active
oldest
votes
INTRODUCTION
First of all each thread has its own mask that specifies which signals it is listening to. When a thread is created it inherits the mask of the thread that is creating it (let me call it the parent thread) that is active when pthread_create is called.
Generally it is better that if a thread is listening to a signal then the others should not, unless you want to have many threads that do the same stuff (for example when processing a connection request in a server to process many requests simultaneously). In this way you always know which thread is processing the signal. Otherwise you do not have any idea which thread is receiving the signal and which part of the program is executing: it becomes impossible to debug (an example is your own question).
To change the mask of the child thread that is being created from the parent thread you create a new mask, you set it active, create a new thread with pthread_create and then in the parent thread set the previous mask active again (see the code at the end of the answer).
EDIT: According to this post it is better to use sigaction() instead of signal. In modern systems signal() is implemented with sigaction() so there should not be any difference. However if its old implementation is used, problems might arise.
ANSWER
So signal only interrupt thread instead of the whole process if there
are multi-threading?
NO: Signals are just signals, they do not do anything. Actions associated to signals have the power to do stuff, including stopping the program or terminating the thread. Each signal has a default action associated and the default action for SIGINT is to interrupt the process.
With you handler you are overwriting the default action. So it will not stop the program anymore but it will do what you have specified in the thread function.
In the first case you have only one thread, the main one, which is an infinite loop, it always catch the signal as long as he is alive so that's why the behavior. If you resend the signal, the signal is momentarily blocked until the signal handler ends the execution. Nevertheless if many signals are sent while the handler is executing, you can loose some signals.
In fact as explained here, blocked signals are set to pending, but not queued. The term pending means that the operating system remembers that there is a signal waiting to be delivered at the next opportunity by setting a flag, and not queued means that it does this by setting a flag somewhere, but not by keeping an exact record of how many signals have arrived.
So if the signals is sent once, 5 times or more (try to press CTRL+C more times with your program: I have tried) while the signal handler is executing it produces the exactly same behaviour.
In your second case you have 3 threads: the main one, t1, and t2: all of them are enabled to see the signal SIGINT and all of them have associated the same signal handler. If you press 3 times one after the other all three of them will execute the handler: that is why you don't see any delay. If you press very very fast though and more than 3 times (the number of threads listening to that signal) I think you will see something similar to the first behaviour.
I will end my answer with the code I posted in a question where I was setting masks so that some signals were caught only by the main thread:
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDsn");
...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLERn");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threadsn");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 createdn");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
/*empty the omask set from all signals */
sigemptyset(&omask);
/*add the signals to the omask*/
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
/*unblock all signals in omask*/
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signaln");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threadsn");
pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and processn");
exit(0);
}
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safegetpid(2)orpthread_selffunctions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and thekill(2)function with negative PIDs.
– Louis Langholtz
Dec 27 '18 at 15:04
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
add a comment |
No matter how many threads the process has, some thread catches the signal and runs the signal handler while the other threads (if any) go on about their business. The signal is sent to the process, but what the process does when it gets the signal is dependent on how the process, and the threads in, configured its signal handlers.
The full rules are quite complicated and I think it's safe to say that very few programmers bother to full understand them and generally avoid signals except for very limited purposes. See here for more details.
add a comment |
So signal only interrupt thread instead of the whole process if there are multi-threading?
Yes. A signal interrupts a single thread of execution. At least according to the POSIX standard. C standard itself doesn't specify behaviour of processes or threads.
If a signal is generated for a multi threaded process as opposed to being generated for particular thread, the signal will be delivered to exactly one of the threads belonging to that process (unless the signal is blocked by all threads).
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53850202%2fsignal-handler-and-multithreading%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
INTRODUCTION
First of all each thread has its own mask that specifies which signals it is listening to. When a thread is created it inherits the mask of the thread that is creating it (let me call it the parent thread) that is active when pthread_create is called.
Generally it is better that if a thread is listening to a signal then the others should not, unless you want to have many threads that do the same stuff (for example when processing a connection request in a server to process many requests simultaneously). In this way you always know which thread is processing the signal. Otherwise you do not have any idea which thread is receiving the signal and which part of the program is executing: it becomes impossible to debug (an example is your own question).
To change the mask of the child thread that is being created from the parent thread you create a new mask, you set it active, create a new thread with pthread_create and then in the parent thread set the previous mask active again (see the code at the end of the answer).
EDIT: According to this post it is better to use sigaction() instead of signal. In modern systems signal() is implemented with sigaction() so there should not be any difference. However if its old implementation is used, problems might arise.
ANSWER
So signal only interrupt thread instead of the whole process if there
are multi-threading?
NO: Signals are just signals, they do not do anything. Actions associated to signals have the power to do stuff, including stopping the program or terminating the thread. Each signal has a default action associated and the default action for SIGINT is to interrupt the process.
With you handler you are overwriting the default action. So it will not stop the program anymore but it will do what you have specified in the thread function.
In the first case you have only one thread, the main one, which is an infinite loop, it always catch the signal as long as he is alive so that's why the behavior. If you resend the signal, the signal is momentarily blocked until the signal handler ends the execution. Nevertheless if many signals are sent while the handler is executing, you can loose some signals.
In fact as explained here, blocked signals are set to pending, but not queued. The term pending means that the operating system remembers that there is a signal waiting to be delivered at the next opportunity by setting a flag, and not queued means that it does this by setting a flag somewhere, but not by keeping an exact record of how many signals have arrived.
So if the signals is sent once, 5 times or more (try to press CTRL+C more times with your program: I have tried) while the signal handler is executing it produces the exactly same behaviour.
In your second case you have 3 threads: the main one, t1, and t2: all of them are enabled to see the signal SIGINT and all of them have associated the same signal handler. If you press 3 times one after the other all three of them will execute the handler: that is why you don't see any delay. If you press very very fast though and more than 3 times (the number of threads listening to that signal) I think you will see something similar to the first behaviour.
I will end my answer with the code I posted in a question where I was setting masks so that some signals were caught only by the main thread:
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDsn");
...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLERn");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threadsn");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 createdn");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
/*empty the omask set from all signals */
sigemptyset(&omask);
/*add the signals to the omask*/
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
/*unblock all signals in omask*/
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signaln");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threadsn");
pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and processn");
exit(0);
}
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safegetpid(2)orpthread_selffunctions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and thekill(2)function with negative PIDs.
– Louis Langholtz
Dec 27 '18 at 15:04
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
add a comment |
INTRODUCTION
First of all each thread has its own mask that specifies which signals it is listening to. When a thread is created it inherits the mask of the thread that is creating it (let me call it the parent thread) that is active when pthread_create is called.
Generally it is better that if a thread is listening to a signal then the others should not, unless you want to have many threads that do the same stuff (for example when processing a connection request in a server to process many requests simultaneously). In this way you always know which thread is processing the signal. Otherwise you do not have any idea which thread is receiving the signal and which part of the program is executing: it becomes impossible to debug (an example is your own question).
To change the mask of the child thread that is being created from the parent thread you create a new mask, you set it active, create a new thread with pthread_create and then in the parent thread set the previous mask active again (see the code at the end of the answer).
EDIT: According to this post it is better to use sigaction() instead of signal. In modern systems signal() is implemented with sigaction() so there should not be any difference. However if its old implementation is used, problems might arise.
ANSWER
So signal only interrupt thread instead of the whole process if there
are multi-threading?
NO: Signals are just signals, they do not do anything. Actions associated to signals have the power to do stuff, including stopping the program or terminating the thread. Each signal has a default action associated and the default action for SIGINT is to interrupt the process.
With you handler you are overwriting the default action. So it will not stop the program anymore but it will do what you have specified in the thread function.
In the first case you have only one thread, the main one, which is an infinite loop, it always catch the signal as long as he is alive so that's why the behavior. If you resend the signal, the signal is momentarily blocked until the signal handler ends the execution. Nevertheless if many signals are sent while the handler is executing, you can loose some signals.
In fact as explained here, blocked signals are set to pending, but not queued. The term pending means that the operating system remembers that there is a signal waiting to be delivered at the next opportunity by setting a flag, and not queued means that it does this by setting a flag somewhere, but not by keeping an exact record of how many signals have arrived.
So if the signals is sent once, 5 times or more (try to press CTRL+C more times with your program: I have tried) while the signal handler is executing it produces the exactly same behaviour.
In your second case you have 3 threads: the main one, t1, and t2: all of them are enabled to see the signal SIGINT and all of them have associated the same signal handler. If you press 3 times one after the other all three of them will execute the handler: that is why you don't see any delay. If you press very very fast though and more than 3 times (the number of threads listening to that signal) I think you will see something similar to the first behaviour.
I will end my answer with the code I posted in a question where I was setting masks so that some signals were caught only by the main thread:
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDsn");
...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLERn");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threadsn");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 createdn");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
/*empty the omask set from all signals */
sigemptyset(&omask);
/*add the signals to the omask*/
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
/*unblock all signals in omask*/
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signaln");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threadsn");
pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and processn");
exit(0);
}
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safegetpid(2)orpthread_selffunctions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and thekill(2)function with negative PIDs.
– Louis Langholtz
Dec 27 '18 at 15:04
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
add a comment |
INTRODUCTION
First of all each thread has its own mask that specifies which signals it is listening to. When a thread is created it inherits the mask of the thread that is creating it (let me call it the parent thread) that is active when pthread_create is called.
Generally it is better that if a thread is listening to a signal then the others should not, unless you want to have many threads that do the same stuff (for example when processing a connection request in a server to process many requests simultaneously). In this way you always know which thread is processing the signal. Otherwise you do not have any idea which thread is receiving the signal and which part of the program is executing: it becomes impossible to debug (an example is your own question).
To change the mask of the child thread that is being created from the parent thread you create a new mask, you set it active, create a new thread with pthread_create and then in the parent thread set the previous mask active again (see the code at the end of the answer).
EDIT: According to this post it is better to use sigaction() instead of signal. In modern systems signal() is implemented with sigaction() so there should not be any difference. However if its old implementation is used, problems might arise.
ANSWER
So signal only interrupt thread instead of the whole process if there
are multi-threading?
NO: Signals are just signals, they do not do anything. Actions associated to signals have the power to do stuff, including stopping the program or terminating the thread. Each signal has a default action associated and the default action for SIGINT is to interrupt the process.
With you handler you are overwriting the default action. So it will not stop the program anymore but it will do what you have specified in the thread function.
In the first case you have only one thread, the main one, which is an infinite loop, it always catch the signal as long as he is alive so that's why the behavior. If you resend the signal, the signal is momentarily blocked until the signal handler ends the execution. Nevertheless if many signals are sent while the handler is executing, you can loose some signals.
In fact as explained here, blocked signals are set to pending, but not queued. The term pending means that the operating system remembers that there is a signal waiting to be delivered at the next opportunity by setting a flag, and not queued means that it does this by setting a flag somewhere, but not by keeping an exact record of how many signals have arrived.
So if the signals is sent once, 5 times or more (try to press CTRL+C more times with your program: I have tried) while the signal handler is executing it produces the exactly same behaviour.
In your second case you have 3 threads: the main one, t1, and t2: all of them are enabled to see the signal SIGINT and all of them have associated the same signal handler. If you press 3 times one after the other all three of them will execute the handler: that is why you don't see any delay. If you press very very fast though and more than 3 times (the number of threads listening to that signal) I think you will see something similar to the first behaviour.
I will end my answer with the code I posted in a question where I was setting masks so that some signals were caught only by the main thread:
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDsn");
...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLERn");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threadsn");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 createdn");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
/*empty the omask set from all signals */
sigemptyset(&omask);
/*add the signals to the omask*/
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
/*unblock all signals in omask*/
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signaln");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threadsn");
pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and processn");
exit(0);
}
INTRODUCTION
First of all each thread has its own mask that specifies which signals it is listening to. When a thread is created it inherits the mask of the thread that is creating it (let me call it the parent thread) that is active when pthread_create is called.
Generally it is better that if a thread is listening to a signal then the others should not, unless you want to have many threads that do the same stuff (for example when processing a connection request in a server to process many requests simultaneously). In this way you always know which thread is processing the signal. Otherwise you do not have any idea which thread is receiving the signal and which part of the program is executing: it becomes impossible to debug (an example is your own question).
To change the mask of the child thread that is being created from the parent thread you create a new mask, you set it active, create a new thread with pthread_create and then in the parent thread set the previous mask active again (see the code at the end of the answer).
EDIT: According to this post it is better to use sigaction() instead of signal. In modern systems signal() is implemented with sigaction() so there should not be any difference. However if its old implementation is used, problems might arise.
ANSWER
So signal only interrupt thread instead of the whole process if there
are multi-threading?
NO: Signals are just signals, they do not do anything. Actions associated to signals have the power to do stuff, including stopping the program or terminating the thread. Each signal has a default action associated and the default action for SIGINT is to interrupt the process.
With you handler you are overwriting the default action. So it will not stop the program anymore but it will do what you have specified in the thread function.
In the first case you have only one thread, the main one, which is an infinite loop, it always catch the signal as long as he is alive so that's why the behavior. If you resend the signal, the signal is momentarily blocked until the signal handler ends the execution. Nevertheless if many signals are sent while the handler is executing, you can loose some signals.
In fact as explained here, blocked signals are set to pending, but not queued. The term pending means that the operating system remembers that there is a signal waiting to be delivered at the next opportunity by setting a flag, and not queued means that it does this by setting a flag somewhere, but not by keeping an exact record of how many signals have arrived.
So if the signals is sent once, 5 times or more (try to press CTRL+C more times with your program: I have tried) while the signal handler is executing it produces the exactly same behaviour.
In your second case you have 3 threads: the main one, t1, and t2: all of them are enabled to see the signal SIGINT and all of them have associated the same signal handler. If you press 3 times one after the other all three of them will execute the handler: that is why you don't see any delay. If you press very very fast though and more than 3 times (the number of threads listening to that signal) I think you will see something similar to the first behaviour.
I will end my answer with the code I posted in a question where I was setting masks so that some signals were caught only by the main thread:
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDsn");
...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLERn");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threadsn");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %dn", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 createdn");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
/*empty the omask set from all signals */
sigemptyset(&omask);
/*add the signals to the omask*/
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
/*unblock all signals in omask*/
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signaln");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threadsn");
pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and processn");
exit(0);
}
edited Jan 5 at 14:29
answered Dec 19 '18 at 12:33
Francesco BoiFrancesco Boi
2,60522543
2,60522543
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safegetpid(2)orpthread_selffunctions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and thekill(2)function with negative PIDs.
– Louis Langholtz
Dec 27 '18 at 15:04
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
add a comment |
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safegetpid(2)orpthread_selffunctions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and thekill(2)function with negative PIDs.
– Louis Langholtz
Dec 27 '18 at 15:04
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safe
getpid(2) or pthread_self functions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and the kill(2) function with negative PIDs.– Louis Langholtz
Dec 27 '18 at 15:04
+1 on your answer. Here's a couple ideas for improvements: mentioning the async-signal-safe
getpid(2) or pthread_self functions to get idea of thread handler is being invoked for; mentioning how Ctrl-C is typically handled by a shell, process groups, and the kill(2) function with negative PIDs.– Louis Langholtz
Dec 27 '18 at 15:04
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
Thanks... I will check them and see if I can improve it.
– Francesco Boi
Dec 27 '18 at 15:30
add a comment |
No matter how many threads the process has, some thread catches the signal and runs the signal handler while the other threads (if any) go on about their business. The signal is sent to the process, but what the process does when it gets the signal is dependent on how the process, and the threads in, configured its signal handlers.
The full rules are quite complicated and I think it's safe to say that very few programmers bother to full understand them and generally avoid signals except for very limited purposes. See here for more details.
add a comment |
No matter how many threads the process has, some thread catches the signal and runs the signal handler while the other threads (if any) go on about their business. The signal is sent to the process, but what the process does when it gets the signal is dependent on how the process, and the threads in, configured its signal handlers.
The full rules are quite complicated and I think it's safe to say that very few programmers bother to full understand them and generally avoid signals except for very limited purposes. See here for more details.
add a comment |
No matter how many threads the process has, some thread catches the signal and runs the signal handler while the other threads (if any) go on about their business. The signal is sent to the process, but what the process does when it gets the signal is dependent on how the process, and the threads in, configured its signal handlers.
The full rules are quite complicated and I think it's safe to say that very few programmers bother to full understand them and generally avoid signals except for very limited purposes. See here for more details.
No matter how many threads the process has, some thread catches the signal and runs the signal handler while the other threads (if any) go on about their business. The signal is sent to the process, but what the process does when it gets the signal is dependent on how the process, and the threads in, configured its signal handlers.
The full rules are quite complicated and I think it's safe to say that very few programmers bother to full understand them and generally avoid signals except for very limited purposes. See here for more details.
answered Dec 19 '18 at 11:25
David SchwartzDavid Schwartz
138k14144226
138k14144226
add a comment |
add a comment |
So signal only interrupt thread instead of the whole process if there are multi-threading?
Yes. A signal interrupts a single thread of execution. At least according to the POSIX standard. C standard itself doesn't specify behaviour of processes or threads.
If a signal is generated for a multi threaded process as opposed to being generated for particular thread, the signal will be delivered to exactly one of the threads belonging to that process (unless the signal is blocked by all threads).
add a comment |
So signal only interrupt thread instead of the whole process if there are multi-threading?
Yes. A signal interrupts a single thread of execution. At least according to the POSIX standard. C standard itself doesn't specify behaviour of processes or threads.
If a signal is generated for a multi threaded process as opposed to being generated for particular thread, the signal will be delivered to exactly one of the threads belonging to that process (unless the signal is blocked by all threads).
add a comment |
So signal only interrupt thread instead of the whole process if there are multi-threading?
Yes. A signal interrupts a single thread of execution. At least according to the POSIX standard. C standard itself doesn't specify behaviour of processes or threads.
If a signal is generated for a multi threaded process as opposed to being generated for particular thread, the signal will be delivered to exactly one of the threads belonging to that process (unless the signal is blocked by all threads).
So signal only interrupt thread instead of the whole process if there are multi-threading?
Yes. A signal interrupts a single thread of execution. At least according to the POSIX standard. C standard itself doesn't specify behaviour of processes or threads.
If a signal is generated for a multi threaded process as opposed to being generated for particular thread, the signal will be delivered to exactly one of the threads belonging to that process (unless the signal is blocked by all threads).
edited Dec 19 '18 at 11:46
answered Dec 19 '18 at 11:25
eerorikaeerorika
85.4k663132
85.4k663132
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53850202%2fsignal-handler-and-multithreading%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
Your code invokes undefined behavior. Per footnote 183 of the C standard: "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows the calling of async-signal-safe functions from within a signal handler. Using
coutand callingsleep()are not async-signal-safe.– Andrew Henle
Dec 19 '18 at 11:29
1
You don't want to have to handle signals that way. Not ever.
– curiousguy
Dec 19 '18 at 11:43
1
man7.org/linux/man-pages/man7/signal.7.html
– Oliv
Dec 19 '18 at 11:59
@AndrewHenle Yes, you are right. But I need to print something to debug, so I think I have no choice. Using non-reentrant functions in signal handler can be undefined behavior. At least for the code above, it works as expected.
– Yves
Dec 20 '18 at 1:16
1
@Yves On a POSIX system:
write( STDOUT_FILENO, buffer, strlen( buffer ) );OrSTDERR_FILENO, if you prefer. Build a C-style string, then usewrite().– Andrew Henle
Dec 20 '18 at 10:33