Chinaunix首页 | 论坛 | 博客
  • 博客访问: 492420
  • 博文数量: 78
  • 博客积分: 995
  • 博客等级: 准尉
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-15 20:22
个人简介

技术中沉思的时候最快乐,问题得到完美解决的时候最有成就感!

文章分类

全部博文(78)

文章存档

2013年(39)

2012年(37)

2011年(2)

分类: LINUX

2013-03-14 12:10:58

    网上搜下 volatile 的作用是:
    "volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错"
    “一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在”
    “用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份”
    
    有些不好理解,自己理解是:
    在代码中有多线程或多进程访问同一个无保护的变量时候,volatile 起到作用是
    1,防止编译过程中,编译器对某些代码的误解而错误优化;
    2,防止在运行过程中,cpu 对某变量寄存器cache,而导致cache和内存不一致(多线程/进程同时操作某变量)

    volatile 在实际开发中用的很少,在 yifei 代码中,出现在两个地方:

    1,快速锁的锁定义
        typedef volatile yf_atomic_uint_t  yf_atomic_t;
    2,无锁环形队列定义
        typedef struct yf_task_queue_s
        {
            yf_u32_t magic;
            size_t  capacity;
            volatile size_t  read_offset;
            volatile size_t  write_offset;
        }
        yf_task_queue_t;

    说下 yifei 项目中 volatile 的两处使用
    1,快速锁
        原理其实比较简单,就是利用的 volatile+原子操作;说白了,就是判断某个变量是不是等于0,如果等于0,则将他置为1;否则不停循环
        重试;关键需要保证两点:
        i),必须保证多个线程/进程读到的变量是同一个地方的,所以不能有寄存器缓存,所以需要 volatile;
        ii),光有 volatile 还是不行的,因为 volatile 只是保证了读取的地方是一致的,但并不能保证读然后写这一系列操作的原子性,他也保证不
            了,所以怎么实现读+写原子性,需要其他手段,比如代码中各种条件下各种不同的手段:atomic_cmpxchg,__sync_bool_compare_and_swap

        btw: 多线程/进程下 volatile 是有用的,网上看到有些人把 volatile 和加锁混淆在一起,顺便总结下:
        i),如果不加锁,则必须有 volatile ,但光用 volatile 是不够的,必须保证操作的原子性才能避免锁;
        ii),如果加锁(比如用pthread_mutex),则 volatile 是不需要的,加了反而影响效率(寄存器cache被禁了)
        ii),锁本身这一内存数据肯定是 volatile,不管这锁是怎么实现的;

   
    2,无锁环形队列
        生产者消费者模型通常需要一个队列做中介,如果是多线程或多进程实现,是需要加锁的;锁本身有开销,且锁有一定的风险;
        比如:多进程下,如果某进程把持了锁,在未解锁前异常退出,会导致队列锁死;
        在一对一的特殊情况下,其实是可以充分利用环形队列的特点,实现无锁;
        关键点是这两个 volatile ,这里的操作不是原子性的,但因为这一数据结构的特点加使用者的特点(一对一),所以才能保证不需要原子性也
        能避免锁的开销(呃,没说清楚,实现确实比较巧妙,有点”只可意会不可言传“的味道);

    yifei -- 高效可移植 linux c/c++ server 开发基础库
阅读(1228) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~