函数/代码的安全与volatile

来源:互联网 发布:淘宝中老年女夏装 编辑:程序博客网 时间:2024/06/08 17:50

我们在写代码的时候,常常会遇到一些代码安全方面的问题

什么时候会不安全?我们只知道当内存占用量越来越大的时候,函数的运行难免都会出现一些问题

我将函数不安全问题大体分为三类:

1、访问无效内存,资源未释放

那么要问了,什么叫做无效内存

个人认为,这里所说的访问无效内存,也就是我们平时遇到的未定义变量,指针未初始化,访问空指针,溢出的数组,栈等等;

最常见的应该就是我们在malloc如果我们申请的内存空间小于128k,我们的底层就是用do_brk申请内存,之后使用free()是不会释放内存空间的,所以我们依旧可以访问该指针,只不过该指针指向的应该就是我们所说的无效内存。

当我们申请128k以上的内存空间的时候,我们是使用do_mmap申请的内存 ,再调用free(),是会归还内存空间的。



2、在调用函数的时候,被调用的函数,禁止返回局部变量的地址或者引用。

我们知道,在内存空间内,什么是不可共享的? 栈,栈上的数据是独有的,是不可共享的;而我们的函数就是开辟的栈帧,属于栈上的内存空间,所以如果我们调用函数的时候返回的是函数内局部变量的地址或者引用。我们想一下,函数调用完成之后,战阵是要回退的,那我们栈上的地址怎么去寻找呢?你怎么去访问?当然,如果是在其他的内存区域,我们返回地址或者引用是没有问题的。


3、代码的线程安全

这第三点,就是我们最经常忽略的。

我们如何判断一个线程是不是安全的?

首先我们要判断我们的函数是不是可重入函数(因为不可重入函数是不安全的,原因后文讲)

可重入函数: 就是我们程序运行的结果,会因为我们线程调度顺序的不同,而产生不同的结果,也就是我们的代码出现了竞态条件

我们把发生竞态条件的代码段称为临界区代码段,临界区代码段也就是我们访问临近资源的代码段,临界资源就是同一时间只允许一个进程(线程)访问的资源。

对于临界区代码段,我们需要保证它的原子操作,也就是保证我们的操作不能被中断;

为了保证我们临界区代码段的原子操作,我们需要对临界区代码段进行加互斥锁进行控制。


int value=10;

int func()

{

pthread_mutex_lock(&mutex);

        value++;

pthread_mutex_unlock(&mutex);

return value;

}


volatile:

在多线程环境中,不允许线程对其修饰的的变量进行缓存,所以线程读写的数据都是内存数据段的内容

int data=10;

     线程1                                                                线程2

void func()                                                    

{                                                                    data=20;

int a=data;                                                                   

int b=data;

}

我们线程1得知我们内存中数据段内data的值是10,于是就从对数据段中的data进行缓存,缓存在我们线程1中的寄存器中,假如这时我们的线程2对data进行修改,将我们的data修改为20,那么我们的线程1能收到吗?显然不能!虽然我们这种缓存机制提升了我们线程1的效率,但是这正确率保证不了,是不是也没有什么用?所以我们可以将其改为:

volatile int data=10;

     线程1                                                                线程2

void func()                                                    

{                                                                    data=20;

int a=data;                                                                   

int b=data;

}


这样我们就保证线程无法从内存数据段中缓存数据,我们进程1取data的值,然后返回给内存,内存中的data此时没有发生改变;

这时我们的线程2取到data的值,也不能缓存到寄存器,直接对我们data进行修改,这时我们内存中的data变为20,所以我们线程1中的b再取data时,我们的data变成了20;

所以volatile就是保证了我们的寄存器不回去缓存我们内存中数据段的数据,而是每次都要从内存中取值,虽然我们的速度变慢了。但是我们保证了正确率。
















原创粉丝点击