Antonio Ragagnin
Antonio Ragagnin

Reputation: 2327

When I catch a signal with signal(SIGINT,f), is f executed in parallel?

I have C code like this

#include <stdio.h>
#include <unistd.h>
#include <signal.h>


void handler_function(int);
int i=0;
int j=0;
int main() {
    signal(SIGINT,f);
    while(1) {
     /* do something in variable `i` */
    }
}

void f(int signum) {
     /* do something else on variable `i` */
}

Can it produce a data race? i.e. is f executed in parallel (even in a multithread machine) to the main. Or maybe is the main stopped until f finish its execution?

Upvotes: 0

Views: 392

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754190

Unless you use the raise() from Standard C or kill() with the value from getpid() as the PID argument, signal events are asynchronous.

In single-threaded code on a multi-core machine, it means that you cannot tell what is happening in the 'do something to variable i' code. For example, that code might have just fetched the value from i and have incremented it, but not yet saved the incremented value. If the signal handler function f() reads i, modifies it in a different way, saves the result and returns, the original code may now write the incremented value of i instead of using the value modified by f().

This is what leads to the many constraints on what you can do in a signal handler. For example, it is not safe to call printf() in a signal handler because it might need to do memory allocation (malloc()) and yet the signal might have arrived while malloc() was modifying its linked lists of available memory. The second call to malloc() might get thoroughly confused.

So, even in a single-threaded program, you have to be aware and very careful about how you modify global variables.

However, in a single-threaded program, there will be no activity from the main loop while the signal is being handled. Indeed, even in a multi-threaded program, the thread that receives (handles) the signal is suspended while the signal handler is running, but other threads are not suspeded so there could be concurrent activity from other threads. If it matters, make sure the access to the variables is properly serialized.

See also:

Upvotes: 1

merlin
merlin

Reputation: 136

First of all according to the man page of signal() you should not use signal() but sigaction()

The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead. See Portability below.

But one might hope that signal() behaves sanely. However, there might be a data race because main might be interrupted before a store e.g. in a situation like this

if ( i > 10 ) { 
    i += j; 
}
void f(int signum) {
    i = 0;
}

If main is past the compare (or if the according registers do not get update if main was interrupted while compare), main would still to i += j which is a data race.

So where does this leave us? - Don't ever modify globals that get modified elsewhere in signal handlers if you cannot guarantee that the signal handler cannot interrupt this operation (e.g. disable signal handler for certain operations).

Upvotes: 2

Related Questions