线程安全与可重入函数

来源:互联网 发布:广东专业seo外包公司 编辑:程序博客网 时间:2024/06/05 12:57

线程安全及其避免方式

线程安全:当一个函数被多个并发进程反复调用时,它会一直产生正确的结果,称其为线程安全的。若一个函数不是线程安全的,就称其为线程不安全的。
  线程安全就是说多线程访问同一代码,不会产生不确定的结果。线程安全就是多线程访问时,采用加锁机制,当一个线程访问该类的某个数据时,用锁对数据进行保护,其他线程不能访问该数据直到该线程读取完,其他线程才可使用,线程安全不会出现数据不一致或者数据污染。

我们定义四类线程不安全的函数

1.不保护共享变量(临界资源)的函数

这类线程不安全函数可以通过P、V操作来保护共享变量(临界资源)。
优点:调用从程序中不需要进行修改
缺点:同步操作会减慢程序的执行时间

2.保持跨越多个调用的状态函数

用一个伪随机数生成器来说明这类线程不安全函数

unsigned int next = 1;int rand(){    next = next*552553 + 6666666;    return (unsigned int)(next/32484)%3245;}void grand(unsigned int seed){    next = seed;}

  rand函数是线程不安全的,因为当前调用的结果依赖于前次调用的中间结果。当我们调用srand为rand设置一个种子后,我们反复从一个单线程中调用rand,能够预期一个可重复的随机数字序列。但是若有多个线程同时调用rand函数,这样的假设就会出现问题
  使rand函数变为线程安全的方法是重写它。

3.返回指向静态变量指针的函数

  有些函数将计算结果放在静态结构中,并返回一个指向这个结构的指针。若从并发线程中带哦用这些函数可能会发生问题,因为正在被一个线程使用的结果会被另一个线程覆盖
  有两种方法处理这类线程不安全的函数。一是重写函数,使得调用者传递存放结果的结构地址,消除共享数据。二是使用lock-and-copy加锁拷贝,调用互斥锁来保护。

4.调用线程不安全函数的函数

  若一个函数调用一个线程不安全的函数,则自己也会变成一个线程不安全的函数

可重入函数及其特点

  可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

下面举例说明可重入函数与不可重入函数

   A. 可重入函数  void strcpy(char *lpszDest, char *lpszSrc)   {      while(*lpszDest++=*lpszSrc++);      *dest=0;  }  B. 不可重入函数1  char cTemp;//全局变量  void SwapChar1(char *lpcX, char *lpcY)   {      cTemp=*lpcX;      *lpcX=*lpcY;      lpcY=cTemp;//访问了全局变量  }  C. 不可重入函数2  void SwapChar2(char *lpcX,char *lpcY)   {      static char cTemp;//静态局部变量      cTemp=*lpcX;      *lpcX=*lpcY;      lpcY=cTemp;//使用了静态局部变量  }

需要满足下列条件的是可重入函数:

1. 不使用全局变量或静态变量;
2. 不使用用malloc或者new开辟出的空间;
3. 不调用不可重入函数;
4. 不返回静态或全局数据,所有数据都有函数的调用者提供;
5. 使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据;

满足下列条件的函数多数是不可重入的:

1. 函数体内使用了静态的数据结构;
1. 函数体内调用了malloc()或者free()函数;
2. 函数体内调用了标准I/O函数。

可重入函数和线程安全的区别与联系

1. 线程安全是在多个线程情况下引发的,而可重入函数可以只在一个线程的情况下
2. 线程安全不一定是可重入的,而可重入函数则一定是线程安全的
3. 如果一个函数中有全局变量,那么这个线程既不是线程安全的也不是可重入的
4. 如果一个函数当中的数据全身自身栈空间的,则这个函数即使线程安全也是可重入的
5. 如果将对临界资源的访问上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会发生死锁,因此是不可冲入的
6. 线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作互不影响使结果是相同的

原创粉丝点击