volatile关键字的含义是什么?

2020-04-16  本文已影响0人  SpringAlways

volatile关键字会阻止编译器去优化“无法被代码改变”的代码。也就是说有些变量非常敏感,以至于编译器认为它不会被修改,但是它却存在被修改的可能。这时就用到了volatile。下面举一些例子来说明

1、线程
void func()
{
  int a = 1;
  int b= 2;
  print(a + b);
  a = 3;
}

这个输出会是多少呢?如果两个线程在同时执行func,thread1执行到a=3的时候,thread2刚好执行到b=2,那thread2就应该打印出5. 此时这个a就是非常敏感的,没有volatile时,thread1和thread2都打印3,有volatile就是一个3一个5.这对于公共区域的资源是很关键的,比如卖票。volatile在一定程度上起了互斥锁的作用。

2、iOS(mac os) block内存管理 引用计数
struct Block_byref {
    void *isa;
    struct Block_byref *forwarding;
    volatile int32_t flags; // contains ref count
    uint32_t size;
};

我们看到flags变量是由volatile修饰的,注释为包含引用计数。甚至这个flags值在使用的时候,它根本不信任编译器,而是直接强行取地址。

static int32_t latching_incr_int(volatile int32_t *where) {
    while (1) {
        int32_t old_value = *where;
        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
            return BLOCK_REFCOUNT_MASK;
        }
        if (OSAtomicCompareAndSwapInt(old_value, old_value+2, where)) {
            return old_value+2;
        }
    }
}

static bool latching_incr_int_not_deallocating(volatile int32_t *where) {
    while (1) {
        int32_t old_value = *where;
        if (old_value & BLOCK_DEALLOCATING) {
            // if deallocating we can't do this
            return false;
        }
        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
            // if latched, we're leaking this block, and we succeed
            return true;
        }
        if (OSAtomicCompareAndSwapInt(old_value, old_value+2, where)) {
            // otherwise, we must store a new retained value without the deallocating bit set
            return true;
        }
    }
}

可以看到 这两个引用计数加减的函数参数都是volatile int32_t *where 而使用者是latching_incr_int(&src->forwarding->flags);
latching_incr_int(&aBlock->flags);
latching_incr_int_not_deallocating(&aBlock->flags);
使用的是flags的地址,然后这个地址又进行volatile,就是告诉编译器,flags不用你优化,连存放flags的地址,你也不需要优化!

3、看汇编

以x86汇编为例了,该样例摘自维基百科

#include <stdio.h>
int main() {
    int a = 10, b = 100, c = 0, d = 0;
    printf("%d", a + b);
    a = b;
    c = b;
    d = b;
    printf("%d", c + d);
    return 0;
}

gcc -O3 -S without.c -o without.s

.file   "without.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "%d"
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %ecx
    subl    $20, %esp
    movl    $110, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    movl    $200, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    addl    $20, %esp
    xorl    %eax, %eax
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 4.2.1 20070719  [FreeBSD]"
#include <stdio.h>

int main() {
    volatile int a = 10, b = 100, c = 0, d = 0;

    printf("%d", a + b);

    a = b;
    c = b;
    d = b;

    printf("%d", c + d);

    return 0;
}

gcc -S with.c -o with.s

.file   "with.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "%d"
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %ecx
    subl    $36, %esp
    movl    $10, -8(%ebp)
    movl    $100, -12(%ebp)
    movl    $0, -16(%ebp)
    movl    $0, -20(%ebp)
    movl    -8(%ebp), %edx
    movl    -12(%ebp), %eax
    movl    $.LC0, (%esp)
    addl    %edx, %eax
    movl    %eax, 4(%esp)
    call    printf
    movl    -12(%ebp), %eax
    movl    %eax, -8(%ebp)
    movl    -12(%ebp), %eax
    movl    %eax, -16(%ebp)
    movl    -12(%ebp), %eax
    movl    %eax, -20(%ebp)
    movl    -16(%ebp), %edx
    movl    -20(%ebp), %eax
    movl    $.LC0, (%esp)
    addl    %edx, %eax
    movl    %eax, 4(%esp)
    call    printf
    addl    $36, %esp
    xorl    %eax, %eax
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 4.2.1 20070719  [FreeBSD]"
上一篇下一篇

猜你喜欢

热点阅读