线程安全:
线程是系统调度的最小单元,进程是资源分配的最小单元,通常一个进程可以派生出多个线程,各线程间之间相互独立,共享系统资源,提高了CPU的利用率。
线程主要由控制流程和资源使用两部分构成,因此一个不得不面对的问题就是对共享资源的访问。为了确保资源得到正确的使用,开发人员在设计编写程序时需要考虑避免竞争条件和死锁,需要更多地考虑使用线程互斥变量。
线程安全 (Thread-safe) 的函数就是一个在代码层面解决问题比较好的方法,也成为多线程编程中的一个关键技术。如果在多线程并发执行的情况下,一个函数可以安全地被多个线程并发调用,结果依然正确,可以说这个函数是线程安全的。反之,则称之为“非线程安全”函数。
有这么四类函数称为线程不安全的:
1、不保护共享变量的函数;
2、函数状态随着调用改变的函数;
3、返回指向静态变量指针的函数;
4、调用线程不安全函数的函数;
避免:
1、 减少对临界资源的依赖,尽量避免访问全局变量,静态变量或其它共享资源,如果必须要使用共享资源,所有使用到的地方必须要进行互斥锁 (Mutex) 保护。
2、线程安全的函数所调用到的函数也应该是线程安全的,如果所调用的函数不是线程安全的,那么这些函数也必须被互斥锁 (Mutex) 保护。
编译运行:
发现运行结果并不是10000,每次运行结果都不一样,可见线程是不安全的。
可重入函数:
当一个执行流因为异常或者被内核切换而中断正在执行的函数而转为另外一个执行流时,当后者的执行流对同一个函数的操作并不影响前一个执行流恢复后执行函数产生的结果,我们就称这个函数为可重入函数。
如果一个函数符合以下条件之一则是不可重入的:
(1)调用了malloc或free,因为malloc也是用全局链表来管理堆的。
(2)调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
下面给出一个不可重入函数的例子:
运行结果:
正确结果为3,但在g_val为2时Ctrl+C,会出现错误,接收到一个2号信号,会继续执行+1操作,该例中的fun函数是不可重入函数
可重入与线程安全联系和区别:
1、线程安全是在多线程情况下引发的,而可重入函数可以在只有一个线程的情况下发生;
2、线程安全不一定是可重入的,而可重入函数一定是线程安全的;
3、如果一个函数有全局变量,则这个函数不是线程安全也不是可重入的;
4、如果一个函数中的数据全是自身栈空间的,则这个函数既是线程安全也是可重入的;
5、如果将对临界资源的访问加锁,则这个线程是安全的,若重入函数加锁还未释放,则为不可重入。