异步信号安全

异步信号安全

Linux 中可重入这个概念一般只有在 signal 的场景下有意义,叫 async-signal-safe。

很多线程安全的函数都是不可重入的,例如 malloc。可重入的函数一般也是线程安全的,虽然据说有反例,但我没见过。异步可重入跟线程安全不是一回事,虽然有时候两者同时满足。

Posix中大多数函数都是线程安全的,但只有少数是 async-signal-safe。

线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作互不影响使结果是相同的。

在Unix/Linux系统中,signal是以软中断的方式分发的,signal handler可能在任何时候打断一个进程的任意一个线程而执行(如果该线程没有屏蔽该signal的话)。

比如,pthread_mutex_lock函数显然是线程安全的,但是它不是异步可重入的,考虑下面的情况,有这么一段代码:

pthread_mutex_lock(&gLock);
change_some_thing();
pthread_mutex_unlock(&gLock);

假定有一个工作线程A运行到这段代码,调用了pthread_mutex_lock但是还没返回的时候,有个signal产生了,signal handler打断线程A执行,然后在signal handler的上下文中也运行到了这段代码(注意signal handler其实借用了线程A的栈执行代码,这一点很像操作系统内核的中断处理),signal handler调用pthread_mutex_lock的时候,线程A的pthread_mutex_lock可能才执行了一半,因为pthread_mutex_lock不是异步可重入的,所以在signal handler的上下文中的pthread_mutex_lock调用很可能会破坏pthread_mutex_t的内部状态,导致程序死锁等异常行为。

类似的情况还有很多,最后导致的结果也不尽相同。

不过异步可重入应该是Unix/Linux这种支持signal的系统特有的。在Windows下,其实并不存在类似的问题,Windows的C Runtime虽然也有signal这样的函数,但是它更像是为了保持向前兼容而做的模拟,因为Windows的signal是通过特定的线程分发的,所以它不会打断应用的线程。所有线程安全的函数在Windows的signal handler中应该都可以使用。在Windows中,SEH机制更接近Unix/Linux中的signal handler,但是显然SEH更可控一点。

个人并不喜欢Unix/Linux中的signal机制,Unix/Linux中的signal机制更像是一种用户态的中断,当它和多线程机制同时出现的时候,总是显得格格不入。


版权声明:本文为qq_43325061原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>