volatile实例

volatile实例

一、volatile的汇编解释
main.c:
#include <stdio.h>
int a = 100;
void main(){
    while(a == 100){}
    printf("finally...\n");
}



优化要开得比较高,gcc -O2 -S main.c得到
    cmpl    $100, a //先比较a和100
    je  .L4    //相等就跳到L4
..........
    ret
.L4:
    jmp .L4    //L4再跳到L4,就是把和a比较的部分给删了,来了死循环,因为编译器认定了a不会变
..........
    .data
    .align 4
    .type   a, @object
    .size   a, 4
a:
    .long   100

加上了volatile int a = 100就变成了:
.L3:
    movl    a, %eax
    cmpl    $100, %eax
    je  .L3
也是个一直从L3调回L3的过程,但是L3本身包括了对a是否等于100的验证。
总之,volatile至少一点效果是告诉编译器,这个变量别去乱优化,不像你想象的那样。

二、volatile实用举例
对于一中的int a,怎么都想不到要变的方法。改一下就可以了:
#include <stdio.h>
#include <signal.h>
int a = 100;
void handler(int num){
    a = 200;
}
void main(){
    signal(SIGUSR1,handler);
    while(a == 100){}
    printf("finally...\n");
}


gcc -O2 main.c之后执行,kill -SIGUSR1 进程号是没有用的,就像之前说的已经优化成死循环了,改成volatile int a就可以了。

另一个简单的共享内存例子:
//仅作为演示用,异常情况未作处理
#include <sys/shm.h>
#include <stdio.h>
int main(){
    int shmid = shmget(1234,sizeof(char),0666|IPC_CREAT);
    void *shm = shmat(shmid,NULL,0);
    char *pc = shm;
    *pc = 1;
    while(*pc){}
    printf("finally");
    shmdt(shm);
}


汇编代码为:
........
    movb    $1, (%eax)
.L2:
    jmp .L2        //有是自己跳回自己,根本就没有去看*pc的值
........
改下代码得到个反例:
//仅作为演示用,异常情况未作处理
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
    int shmid = shmget(1234,sizeof(char),0666|IPC_CREAT); //共享内存相关函数不多,用法也方便,不熟悉百度也能两下上手
    if(fork() == 0){    //子进程
        sleep(10);    //休息十秒好看打印结果
        void *shm = shmat(shmid,NULL,0); //子进程能从副进程出继承到变量的值,并且往往是写时才复制
        char *pc = shm;
        *pc = 0;
        printf("son:done\n");    //改完了,打印done
        shmdt(shm);
        exit(0);
    }
    void *shm = shmat(shmid,NULL,0);    //不在这之后fork是shm返回的线性地址空间子进程和父进程完全是两码事
    char *pc = shm;
    //volatile char *pc = shm;
    *pc = 1;
    while(*pc){}
    printf("finally");
    shmdt(shm);
}

像预想的那样,非volatile的-O2完全就优化成了死循环,而volatile的则在子进程打印后父进程打印(当然具体退出时间前后不一定)。
总之,编译器往往“聪明反被聪明误”,像上面的a和*pc都是对程序员可预期会变的,但是编译器看不出来,这时就要用volatile明确地告知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值