【进程信号】可重入函数&&volatile关键字

什么叫做可重入函数

可重入函数是指,一个函数在被多个线程调用时,不会因为共享资源的竞争而导致数据不一致等错误。这种函数可以在多线程环境中调用。意思就是说,可重入函数里面的数据都是临时变量,随着函数栈帧的销毁而销毁,一个线程调用这个函数并不会影响其它的线程

如下给出一个可重入函数的例子:

int reentrant_function(int x) {
    int result = x * x;
    return result;
}

这个函数里面所有的变量都是局部变量,并且没有依赖任何全局或者静态变量。

再给出一个非可重入函数的例子:

int global_var = 0;

void non_reentrant_function(int x) {
    global_var = x;
}

这个函数修改了全局变量,在多线程环境下,多个线程同时调用,会导致数据竞争和不一致。所以是非可重入函数。

下面具体介绍可重入函数的特点。

可重入函数的特点

  1. 不使用静态和动态变量:可重入函数被调用时,只会访问局部变量。
  2. 不依赖共享资源:可重入函数不依赖外部资源,如果一定要依赖外部资源,保证在使用前后正确锁定资源
  3. 不调用非可重入函数:如果一个函数内部调用了非可重入函数,那么这个函数也是非可重入函数
  4. 线程安全:可重入函数是线程安全的,但是线程安全的函数不一定是可重入函数。

作用

可重入函数是保证多线程安全编程的一种重要方法,通过保证每次调用之间的状态独立和避免共享资源的竞争来避免很多并发编程中的问题。

volatile关键字

volatile是一个类型关键字,通常用来修饰变量。告诉编译器该变量可能会在程序执行过程中被意外改变,因此编译器不应该对这样的变量进行优化。

为什么要有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的值。

volatile关键字的作用

保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值