什么是线程安全,如何避免?
如果你的程序所在的进程中有多个线程在同时运行,而这些线程可能同时运行一段代码或同时访问一个对象,如果每次运行完这段代码或访问完这个对象之后,所得到的结果和单线程运行的结果一样,而其他变量的值也和预期的保持一致,那么就认为是线程安全的。也就是说当多个线程同时运行同一段代码,不会造成资源的冲突,不会产生错误的结果就是线程安全的。
避免
1.不保护共享变量的函数采用加锁即可。
2.保持跨越多个调用的状态函数。如rand库函数,这种情况下要么重写它,使它不包含任何静态数据,依靠调用者在参数中传递参数信息;或者采用库函数提供的可重入版本,而可重入版本的函数名是在原函数名尾部加上_r,即为rand_r。
3.返回指向静态变量指针的函数。如gethostbyname函数,该函数内部用一个静态变量存储转化结果,函数的返回值指向该静态内存。当并发线程中调用这些函数,因为正在被一个线程使用的结果会被另一个线程悄悄地覆盖了。一种处理方法是可以采用使用线程特定数据来替换静态存储。但是,此替换涉及到动态分配存储,并且会增加调用开支。处理该问题的更好方法是调用方可通过例程的其他输出参数来提供存储。其他输出参数需要gethostbyname() 函数的新接口。即gethostbyname_r()函数。
什么是可重入函数,有什么特点?
可重入函数也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有多个该函数的副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。
特点
1.函数中使用了静态数据或全局数据
2.函数中使用了malloc()或者free()函数 :malloc/free是不可重入的,它们使用全局变量来只向空闲区
3.函数内使用了标准的I/O函数 :标准I/O函数中,很多使用了全局变量
4.进行了浮点运算 :许多的处理器/编译器,浮点运算都是不可重入的
对比线程安全和可重入函数
1.可重入函数一定是线程安全函数
2.线程安全函数不一定是可重入函数(有可能通过互斥机制实现线程安全不安全函数—>线程安全函数的转换等)
3.可重入性要强于线程安全性(相当于函数产生相同结果时可重入性的条件要苛刻)