参考:
1. 摘自 多线程和多进程的区别(小结) http://blog.csdn.net/hairetz/article/details/4281931
要确保函数线程安全,主要需要考虑的是线程之间的共享变量。
属于同一进程的不同线程会共享进程内存空间中的全局区和堆,而私有的线程空间则主要包括栈和寄存器。
因此,对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量、局部静态变量、分配于堆的变量都是共享的。在对这些共享变量进行访问时,如果要保证线程安全,则必须通过加锁的方式。
要确保函数可重入,需满足一下几个条件:
1、不在函数内部使用静态或全局数据
2、不返回静态或全局数据,所有数据都由函数的调用者提供。
3、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。
4、不调用不可重入函数。
可重入与线程安全并不等同,一般说来,可重入的函数一定是线程安全的,但反过来不一定成立。线程安全函数包括了可重入的函数,但不全是可重入函数;
比如:strtok函数是既不可重入的,也不是线程安全的;加锁的strtok不是可重入的,但线程安全;而strtok_r既是可重入的,也是线程安全的。
如果我们的线程函数不是线程安全的,那在多线程调用的情况下,可能导致的后果是显而易见的——共享变量的值由于不同线程的访问,可能发生不可预料的变化,进而导致程序的错误,甚至崩溃。
如何将一个不可重入的函数改写成"可重入的函数"? <根据上面的分析,这里意思包含了线程安全的函数.>
答:把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写它。其实很简单,只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的。
1) 不要使用全局变量。因为别的代码很可能覆盖这些变量值。
2) 在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”。
3) 不能调用其它任何不可重入的函数。
4) 谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。
堆栈操作涉及内存分配,稍不留神就会造成益出导致覆盖其他任务的数据,所以,请谨慎使用堆栈!