赞
踩
可重入函数是指,一个函数在被多个线程调用时,不会因为共享资源的竞争而导致数据不一致等错误。这种函数可以在多线程环境中调用。意思就是说,可重入函数里面的数据都是临时变量,随着函数栈帧的销毁而销毁,一个线程调用这个函数并不会影响其它的线程。
如下给出一个可重入函数的例子:
int reentrant_function(int x) {
int result = x * x;
return result;
}
这个函数里面所有的变量都是局部变量,并且没有依赖任何全局或者静态变量。
再给出一个非可重入函数的例子:
int global_var = 0;
void non_reentrant_function(int x) {
global_var = x;
}
这个函数修改了全局变量,在多线程环境下,多个线程同时调用,会导致数据竞争和不一致。所以是非可重入函数。
下面具体介绍可重入函数的特点。
可重入函数是保证多线程安全编程的一种重要方法,通过保证每次调用之间的状态独立和避免共享资源的竞争来避免很多并发编程中的问题。
volatile是一个类型关键字,通常用来修饰变量。告诉编译器该变量可能会在程序执行过程中被意外改变,因此编译器不应该对这样的变量进行优化。
这就要了解编译器的优化机制。编译器在优化代码的时候,会大概推断出哪些变量在特定的范围内不会改变。对于这样的变量,编译器会把它们的值缓存在寄存器中,这也就不用再去内存上访问,需要的时候就在寄存器上读取。但是,如果一个变量的值是通过硬件中断、另一个线程或信号处理函数来改变的,那么编译器之前缓存在寄存器中的值就不准确了,从而导致程序出现错误的行为。
#include <stdio.h> #include <signal.h> #include <unistd.h> using namespace std; int flag = 0; void myhandler(int sig) { printf("flag to 1\n"); flag = 1; } int main() { signal(2, myhandler); while (!flag) { printf("i am process\n"); sleep(1); } printf("process end\n"); return 0; }
观察上述代码。标准情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while
条件不满足,退出循环,进程退出。
而如果我们编译的时候带上-O2
选项,优化编译1代码,即使按下Ctrl+C也不会退出循环。这是为什么呢?
虽然执行了myhandler,也成功修改了flag的值,但是由于编译器优化,早就将flag的值拷贝到寄存器中了,CPU只会在寄存器中读取flag的值。即使后来通过执行myhandler函数修改了flag的值。
保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。