可重入函数的总结

  • 搞错了,下面说的是线程安全
  • 概念

  可重入函数这个概念是针对多进程,多线程编程中产生的。指的是一个函数被并发调用时,任意一个调用不会影响到它的另一个调用。

  那么什么样的函数又不是可重入的呢?举几个反例,说明可重入函数要规避的东西。下面的1,2两点都是在多线程中出现的问题,进程在fork后静态变量和全局变量是有各自的拷贝,不会出现这样的情况。

  1.   函数中使用静态变量
 1 void foo(void)
 2 {
 3     int n = 10000000;
 4     static int i = 0;
 5
 6     i++;
 7
 8     while ( n-- );
 9     printf("run foo i:%d\n\n",i);
10 }
11
12 void *threadfun1(void *arg)
13 {
14     foo();
15     return (void *)0;
16 }
17
18 void *threadfun2(void *arg)
19 {
20     foo();
21     return (void *)0;
22 }

  首先这个例子里面不单单这个静态变量 i 是一个不可重入的点,其实printf函数的调用也是导致不可重入的另一个原因,但是暂时不考虑printf。2个线程运行起来,按照正常的运行结果,多次运行这个程序,输出应该是一样的,但是运行后发现:

[email protected]:~/test$ ./a
run foo i:2

run foo i:2

[email protected]-laptop:~/test$ ./a
run foo i:2

run foo i:1

[email protected]-laptop:~/test$ ./a
run foo i:1

run foo i:1

运行完全乱套,这是为什么呢?线程有2个,但是静态变量i却是共享的同一个。

  2.  使用全局变量

  若把上面的 i 定义为全局变量也会出现同样的问题,原因也是多个线程共享了同一个数据,没做好竞态资源的访问管理。针对全局变量,可以通过一个互斥锁解决这个问题。

 1 int i = 0;
 2 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
 3 void foo(void)
 4 {
 5     int n = 100000;
 6
 7     pthread_mutex_lock(&mtx);
 8     i++;
 9     while ( n-- );
10     printf("run foo i:%d\n\n",i);
11     pthread_mutex_unlock(&mtx);
12 }

  3.  函数调用了不可重入函数

  这个好理解,比如上面调用了printf,printf本身就是不可重入的,为什么呢?printf函数有一个缓冲区的概念,这个缓冲区是进程里共享的,假设printf输入到一半,被另一个线程的printf抢来输出,结果输出乱套了,标准IO函数都是不可重入的它们使用了静态变量,全局变量等。像malloc,free都是不可重入的。

时间: 2024-07-30 06:43:12

可重入函数的总结的相关文章

线程安全和可重入函数

一.线程安全 1.线程安全函数:C语言中局部变量是在栈中分配的,任何未使用静态数据或其他共享资源的函数都是线程安全的. (1)对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量.局部静态变量.分配于堆的变量都是共享的,即是非线程安全的. (2) 在对这些共享变量进行访 问时,如果要保证线程安全,则必须通过加锁的方式. 2.线程安全的:                   如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的.                  

可重入函数与不可重入函数

参考:http://blog.csdn.net/wenhui_/article/details/6889013 重入:重新进入 区别:多个任务能否同时调用一个函数,例如操作系统在进程调度过程中,或者单片机.处理器等的中断的时候会发生重入的现象 满足下面条件之一的多数是不可重入函数:(1)使用了静态数据结构:(2)调用了malloc或free:(3)调用了标准I/O函数,比如printf: 标准io库很多实现都以不可重入的方式使用全局数据结构:(4)进行了浮点运算.许多的处理器/编译器中,浮点一般

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

1.可重入函数 可重入函数即表示可以被多个执行流重复进入,意味着只使用自己栈上的变量,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰. 一个不可重入函数的例子: int global; int fun( int a ) { int temp; global = a; temp = gloabl*2; return temp; } global是一个全局变量,若进程a运行这段代码传入的参数是2,预期的结果是4:进程b也运行这段代码,传入的参数是3,由于操作系统的进程调

可重入函数与线程安全

线程安全: 假如在一个函数中它是这么写的,在一个全局链表上存放数据,在单线程模式下,我们先new一个新的节点然后让head->next指向这个节点,这种场景在多线程场景下会是这样的过程,线程一new了一个节点,然后cpu转去执行线程二,线程二new一个节点后head->next指向线程二,然后执行线程一,线程一的head->next也指向它刚刚new出来的节点,这就导致一个head指向了两个节点,这也就是线程安全的问题. 导致线程安全问题需要满足下面两个条件: 1>:一定是发生在多

线程安全与可重入函数

一.线程安全    在目前线程是操作系统调度的最小单元,进程是资源分配的最小单元.在大多数操作系统中,一个进程可以同时派生出多个线程.这些线程独立执行,共享进程的资源.线程主要由控制流程和资源使用两部分构成,因此一个不得不面对的问题就是对共享资源的访问.为了确保资源得到正确的使用,我们在设计编写程序时需要考虑避免竞争条件和死锁,需要更多地考虑使用线程互斥变量. 如果我们的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的

可重入函数(转)

在实时系统的设计中,经常会出现多个任务调用同一个函数的情况.如果有一个函数不幸被设计成为这样:那么不同任务调用这个函数时可能修改其他任务调用这个函数的数据,从而导致不可预料的后果.这样的函数是不安全的函数,也叫不可重入函数. 相反,肯定有一个安全的函数,这个安全的函数又叫可重入函数.那么什么是可重入函数呢?所谓可重入是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错. 一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执

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

概念 重入:即重复调用,函数被不同的流调用,有可能会出现第一次调用还没返回时就再次进入该函数开始下一次调用. 可重入:当程序被多个线程反复执行,产生的结果正确. 如果一个函数只访问自己的局部变量或参数,称为可重入函数. 不可重入:当程序被多个线程反复调用,产生的结果出错. 当函数访问一个全局的变量或者参数时,有可能因为重入而造成混乱,像这样的函数称为不可重入函数. 线性安全:一般来说,一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果. 可重入函数与线程安全的区别

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

一.线程安全 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的.  或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题. 线程安全问题都是由全局变量及静态变量引起的. 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线程同时执

10.6 可重入函数

当一个信号捕获到并开始被进程处理的时候,进程正常执行的指令序列将被信号处理函数临时中断,进程立即转到信号处理函数中开始执行,如果信号处理函数返回(而不是调用exit或者是longjmp等),然后在进入信号处理函数之前进程正在执行的指令序列将会接着执行,但是在信号处理函数中,我们无法获知在信号被捕获的时候进程正在执行那一段代码,如果进程正在使用函数malloc在其堆上分配额外的内存的过程中会发生什么呢?或者是进程正在调用一个函数的过程中,比如说getpwnam将会发生什么呢?函数getpwnam会

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

一. 线程安全 前面提到过线程的同步与互斥,也就是当两个线程同时访问到同一个临界资源的时候,如果对临界资源的操作不是原子的就会产生冲突,使得结果并不如最终预期的那样,比如如下的程序: #include <stdio.h> #include <pthread.h> int g_val = 0; void* fun(void *arg) {     int i = 0;     while(i++ < 500)     {            int tmp = g_val;