Race conditions can also occur in traditional, single-threaded programs - Clarity

I don't think one can call it a race condition in the classical meaning. Race conditions have a somewhat stochastic behavior, depending on the scheduler policy and timings.

The author is probably talking about bugs that can arise when the same object/resource is accessed from multiple recursive calls. But this behavior is completely deterministic and manageable.

Signals on the other hand is a different story as they occur asynchronously and can apparently interrupt some data processing in the middle and trigger some other processing on that data, corrupting it when returned to the interrupted task.


A signal handler can be called at any time without warning, and it potentially can access any global state in the program.

So, suppose your program has some global flag, that the signal handler sets in response to,... I don't know,... SIGINT. And your program checks the flag before each call to f(x).

if (! flag) {
    f(x);
}

That's a data race. There is no guarantee that f(x) will not be called after the signal happens because the signal could sneak in at any time, including right after the "main" program tests the flag.


First it is important to understand what a race condition is. The definition given by Wikipedia is:

Race conditions arise in software when an application depends on the sequence or timing of processes or threads for it to operate properly.

The important thing to note is that a program can behave both properly and improperly based on timing or ordering of execution.


We can fairly easily create "dummy" race conditions in single threaded programs under this definition.

bool isnow(time_t then) {
    time_t now = time(0);
    return now == then;
}

The above function is a very dumb example and while mostly it will not work, sometimes it will give the correct answer. The correct vs. incorrect behavior depends entirely on timing and so represents a race condition on a single thread.


Taking it a step further we can write another dummy program.

bool printHello() {
    sleep(10);
    printf("Hello\n");
}

The expected behavior of the above program is to print "Hello" after waiting 10 seconds.

If we send a SIGINT signal 11 seconds after calling our function, everything behaves as expected. If we send a SIGINT signal 3 seconds after calling our function, the program behaves improperly and does not print "Hello".

The only difference between the correct and incorrect behavior was the timing of the SIGINT signal. Thus, a race condition was introduced by signal handling.