How does the compiler or OS distinguish between sig_atomic_t type and a normal int type variable, and ensures that the operation will be atomic? Programs using both have sam
Programs using both have same assembler code. How extra care is taken to make the operation atomic?
Although this is an old question, I think it's still worth addressing this part of the question specifically. On Linux, sig_atomic_t
is provided by glibc. sig_atomic_t
in glibc is a typedef for int
and has no special treatment (as of this post). The glibc docs address this:
In practice, you can assume that int is atomic. You can also assume that pointer types are atomic; that is very convenient. Both of these assumptions are true on all of the machines that the GNU C Library supports and on all POSIX systems we know of.
In other words, it just so happens that regular int
already satisfies the requirements of sig_atomic_t
on all the platforms that glibc supports and no special support is needed. Nonetheless, the C and POSIX standards mandate sig_atomic_t
because there could be some exotic machine on which we want to implement C and POSIX for which int
does not fulfill the requirements of sig_atomic_t
.
This data type seems to be atomic.
From here:
24.4.7.2 Atomic Types To avoid uncertainty about interrupting access to a variable, you can use a particular data type for which access is always atomic: sig_atomic_t. Reading and writing this data type is guaranteed to happen in a single instruction, so there’s no way for a handler to run “in the middle” of an access.
The type sig_atomic_t is always an integer data type, but which one it is, and how many bits it contains, may vary from machine to machine.
Data Type: sig_atomic_t This is an integer data type. Objects of this type are always accessed atomically.
In practice, you can assume that int is atomic. You can also assume that pointer types are atomic; that is very convenient. Both of these assumptions are true on all of the machines that the GNU C Library supports and on all POSIX systems we know of.
sig_atomic_t
is often just a typedef
(to some system specific integral type, generally int
or long
). And it is very important to use volatile sig_atomic_t
(not just sig_atomic_t
alone).
When you add the volatile
keyword, the compiler has to avoid a lot of optimizations.
The recent C11 standard added _Atomic
and <stdatomic.h>
. You need a very recent GCC (e.g. 4.9) to have it supported.
sig_atomic_t
is not an atomic data type. It is just the data type that you are allowed to use in the context of a signal handler, that is all. So better read the name as "atomic relative to signal handling".
To guarantee communication with and from a signal handler, only one of the properties of atomic data types is needed, namely the fact that read and update will always see a consistent value. Other data types (such as perhaps long long
) could be written with several assembler instructions for the lower and higher part, e.g. sig_atomic_t
is guaranteed to be read and written in one go.
So a platform may choose any integer base type as sig_atomic_t
for which it can make the guarantee that volatile sig_atomic_t
can be safely used in signal handlers. Many platforms chose int
for this, because they know that for them int
is written with a single instruction.
The latest C standard, C11, has atomic types, but which are a completely different thing. Some of them (those that are "lockfree") may also be used in signal handlers, but that again is a completely different story.
Note that sig_atomic_t
is not thread-safe, only async-signal safe.
Atomics involve two types of barriers:
volatile
keyword does.For comprehensive treatment of the subject watch atomic Weapons: The C++ Memory Model and Modern Hardware.