linux系统编程之基础必备(六):可重入函数、sig
是编译器优化得有错误吗?不是的。设想一下,如果程序只有单一的执行流程,只要当前执行流程没有改变a的值,a的值就没有理由会变,不需要反复从内存读取,因此上面的两条指令和while(!a);循环是等价的,并且优化之后省去了每次循环读内存的操作,效率非常高。
所以不能说编译器做错了,只能说编译器无法识别程序中存在多个执行流程。之所以程序中存在多个执行流程,是因为调用了特定平台上的特定库函数,比如sigaction、pthread_create,这些不是C语言本身的规范,不归编译器管,程序员应该自己处理这些问题。
C语言提供了volatile限定符,如果将上述变量定义为volatile sig_atomic_t a=0;那么即使指定了优化选项,编译器也不会优化掉对变量a内存单元的读写。
对于程序中存在多个执行流程访问同一全局变量的情况,volatile限定符是必要的,此外,虽然程序只有单一的执行流程,但是变量属于以下情况之一的,也需要volatile限定:
变量的内存单元中的数据不需要写操作就可以自己发生变化,每次读上来的值都可能不一样;
即使多次向变量的内存单元中写数据,只写不读,也并不是在做无用功,而是有特殊意义的;
什么样的内存单元会具有这样的特性呢?肯定不是普通的内存,而是映射到内存地址空间的硬件寄存器,例如串口的
接收寄存器属于上述第一种情况,而发送寄存器属于上述第二种情况。
sig_atomic_t类型的变量应该总是加上volatile限定符,因为要使用sig_atomic_t类型的理由也正是
要加volatile限定符的理由。
对于多线程的程序,访问冲突的问题是很普遍的,解决的办法是引入锁,获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程,没有获得锁的线程只能等待而不能访问共享数据,这样“读-修改-写”三步操作组成一个原子操作,要么都执行,要么都不执行,不会执行到中间被打断,也不会在其它处理器上并行做这个操作。
评论