Chinaunix首页 | 论坛 | 博客
  • 博客访问: 750130
  • 博文数量: 116
  • 博客积分: 923
  • 博客等级: 准尉
  • 技术积分: 1635
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-06 21:43
个人简介

一直帮老板搬运代码!!!

文章分类
文章存档

2013年(47)

2012年(69)

分类: LINUX

2012-07-09 11:23:11

volatile 变量修饰的使用:

extern volatile ngx_str_t    ngx_cached_err_log_time;
多线程中,作为循环判断的变量,都要使用 volatile 进行修饰,因为每个线程栈里面都有寄存器的存在;方法的
调用,方法里面的每个变量首先放到寄存器里面,然后在方法推出的时候,保存到内存里面。多 线程,如果不这
样做,那么访问的只是自己寄存器的内容,会有死循环出现。这样做后,那么每次访问都访问内存的内容,实时
改变就没有问题了!

//一般说来,volatile用在如下的几个地方:
//1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
//2、多任务环境下各任务间共享的标志应该加volatile;
//3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
//需要注意的是,没有volatile也可能能正常运行,但是可能修改了编译器的优化级别之后就又不能正常运行了。因此经常会出现debug版本正常,但是 release版本却不能正常的问题。所以为了安全起见,只要是等待别的程序修改某个变量的话,就加上volatile关键字。
typedef volatile ngx_atomic_uint_t  ngx_atomic_t;

restrict的使用: FILE *fopen(const char * restrict filename, const char * restrict mode);

restrict 用于修饰指针类型,只能修饰指针类型,保证指针的唯一性;同时对编译进行优化,使得多步计算
变成一步等。比如复杂的指针值的计算或拷贝等保证指针的唯一指向,那么使用它。

#define ngx_memory_barrier()    __asm__ volatile ("" ::: "memory") //内嵌汇编,内存做了改动,(memory)主要保证执行顺序一直,有时是不一致的
__asm__用于指示编译器在此插入汇编语句
__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。

关于barrier()宏实际上也是优化屏障:
#define barrier() __asm__ __volatile__("": : :"memory")
CPU越过内存屏障后,将刷新自己对存储器的缓冲状态。这条语句实际上不生成任何代码,但可使gcc在barrier()之后刷新寄存器对变量的分配。    
例1:
                1        int a = 5, b = 6;
                2        barrier();
                3        a = b;
     
            在line 3,GCC不会用存放b的寄存器给a赋值,而是重新读内存中的b值,赋值给a。
它在进程上下文中将一个元素插入一个单向链表:
new->next=i->next;
wmb();
i->next=new;
同时,如果不加锁地遍历这个单向链表。或者在遍历链表时已经可以看到new,或者new还不在该链表中。两个内存写
事件的顺序必须按照程序顺序进行。否则可能new的next指针将指向一个无效地址,就很可能出现 OOPS!

如果一个内联汇编语句的Clobber/Modify域存在"memory",那么GCC会保证在此内联汇编之前,如果某个内存的内容被装入了寄存器,那么在这个内联汇编之后,如果需要使用这个内存处的内容,就会直接到这个内存处重新读取,而不是使用被存放在寄存器中的拷贝。因为这个 时候寄存器中的拷贝已经很可能和内存处的内容不一致了。

这只是使用"memory"时,GCC会保证做到的一点,但这并不是全部。因为使用"memory"是向GCC声明内存发生了变化,而内存发生变化带来的影响并不止这一点。

例如:

int main(int __argc, char* __argv[])
        {
        int* __p = (int*)__argc;
        (*__p) = 9999;
        __asm__("":::"memory");
        if((*__p) == 9999)
        return 5;
        return (*__p);
        }

本例中,如果没有那条内联汇编语句,那个if语句的判断条件就完全是一句废话。GCC在优化时会意识到这一点,而直接只生成return 5的汇编代码,而不会再生成if语句的相关代码,而不会生成return (*__p)的相关代码。但你加上了这条内联汇编语句,它除了声明内存变化之外,什么都没有做。但GCC此时就不能简单的认为它不需要判断都知道 (*__p)一定与9999相等,它只有老老实实生成这条if语句的汇编代码,一起相关的两个return语句相关代码。

另外在linux内核中内存屏障也是基于它实现的include/asm/system.h中

# define barrier() _asm__volatile_("": : :"memory")

主要是保证程序的执行遵循顺序一致性。呵呵,有的时候你写代码的顺序,不一定是最终执行的顺序,这个是处理器有关的。

“memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。”

个人总结:指针操作后,再赋值给其他变量时使用和变量间的赋值时使用

offsetof

定义如下:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

作用:得到结构体s中成员变量m的偏移值

使用有三个好处:

1、如果传递参数时,使用&结构。成员,会使人误认为是结构,就是代码不清晰

2、如果传递的是浮点,如6.2,如果是跨平台那么会有意想不到的事情发生

3、不使用,体现不了结构的硬件特征

阅读(1334) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~