可重入 与 线程安全
https://en.wikipedia.org/wiki/Reentrancy_(computing)
可重入 和 线程安全 是两个不同的概念。
The key for avoiding confusion is that reentrant refers to only one thread executing. It is a concept from the time when no multitasking operating systems existed.
Reentrant means you can interrupt it and call it again before the previous incarnation ended.
The previous invocations may resume correct execution before the reentered invocation completes. 这一条好像达不到
示例:Thread-safe but not reentrant
_Thread_local int tmp;
void swap(int* x, int* y)
{
tmp = *x;
*x = *y;
*y = tmp; /* Hardware interrupt might invoke isr() here. */
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
示例:Reentrant but not thread-safe
int tmp;
void swap(int* x, int* y)
{
/* Save global variable. */
int s;
s = tmp;
tmp = *x;
*x = *y;
*y = tmp; /* Hardware interrupt might invoke isr() here. */
/* Restore global variable. */
tmp = s;
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Rules for reentrancy:
- Reentrant code may not hold any static or global non-constant data.
- The C standard and SUSv3 provide sig_atomic_t for this purpose, although with guarantees only for simple reads and writes, not for incrementing or decrementing.
- More complex atomic operations are available in C11, which provides stdatomic.h.
- Reentrant code may not modify itself.
- Reentrant code may not call non-reentrant computer programs or routines.
异步信号安全函数列表:http://man7.org/linux/man-pages/man7/signal-safety.7.html
malloc 不可重入,但线程安全。
malloc的实现中应该用到了mutex : http://man7.org/linux/man-pages/man3/malloc.3.html
lock(mutex);
/* Stuff. */
unlock(mutex);
printf 不可重入,但线程安全。
Any output stream usually employs a global buffer attached to the resource data are sent to (a buffer for terminal, or for a file). The print process is usually a sequence of copying data to buffer and flushing the buffer afterwards. This buffer should be protected by locks in the same way malloc does. Therefore, printf is also non-reentrant.