大家都写过C语言中的函数,但有没有想过,你编写的函数在同一个时刻是否允许被多个调用者调用呢?是不是不管谁来调用,有多少个调用者同时调用,都能给出一致的表现,返回一致的结果?
一个函数在不同的调用时刻,会表现不一致!?这个比较奇怪,函数不是已经写好的吗? 怎么会表现出不同的行为呢?另外,我怎么可能在一个程序里面多个地方同时调用同一个函数呢?
其一,答案很简单。函数可能使用了能长期存活的静态数据,俗称老不死数据。为什么我要给他取这个难听的名字,因为静态数据不仅会是的函数每次调用彼此耦合牵连(除非你是有意而为之),而且会在不调用的时候占着内存不拉shi,而且会让并发任务极容易产生竞态,不利于生产!
函数还可能是一个使用了别的使用了老不死数据的函数的函数。(此句充分展现了我是一个能定义嵌套递归概念的合格码农的基本素养)
函数里面的数据还可能直接受制于硬件条件。这在嵌入式系统代码中也是很常见D。
其二,你的程序很可能是一个多线程并发的实例,因此多个地方同时调用同一个函数的情况,很普遍。
综上所述的函数行为总结一个概念就是:在多次调用中(不管是否同时)行为变现一致的函数,被称为可重入函数,否则被称为不可重入函数。
POSIX.1-20001标准规定,所有的标准库函数都必须是可重入函数,除了以下这些:
正如其名所提示的,我们在程序中,同时调用这些函数有可能会产生不一致的结果,产生这样结果的原因有三,上面已经提到,用比较官方严肃的语言来表述如下:
一是因为函数内部使用了共享资源,比如全局变量、环境变量。
二是因为函数内部调用了其他不可重入函数。
三是因为函数执行结果与某硬件设备相关。
从这点出发,如果你想要写一个线程安全的可重入函数的话,只要遵循以下原则就行了:
A) 不使用任何静态(老不死)数据,只使用局部变量或者堆内存。
B) 不调用上表中的任何非线程安全的不可重入函数。
如果不能同时满足以上两个条件,可以使用信号量、互斥锁等机制来确保使用静态数据或者调用不可重入函数时的互斥效果。其实,这也是编写多线程程序必须要注意的地方啦!