volatile限定符从性能的角度取消了编译器的优化,每次读取数据直接从内存中读取,不从编译器中读去内容

Linux下gcc编译器优化:O0无优化 O1缺省,O3最高优化

如以下示例:

      wKiom1ctkbjRX0rnAAA1ATGqXWk880.png

主函数与信号处理函数同时对全局变量进行修改和判断。在主函数中因while循环对该全局变量的值只做判断,因此编译器默认的将该变量从内存中拿到寄存器中后,此后直接从寄存器中读取进行判断,相当于一个寄存器变量,而调用信号处理函数之后对该变量在内存中进行了修改,而并未修改寄存器中的值,因此造成了不一致。而对该变量加了volatile限定符后就直接从内存中读取或修改数据。

竞态条件:由于异步事件(指拥有更高优先级的)任何时候都有可能发生,如果写程序时考虑不到位,就有可能由于时序问题导致错误,这就是竞态条件。

wKiom1ctlV7B2Ig3AABit_MJIV8686.png

上边为自己编写的my_sleep函数;1)先注册信号处理函数2)设置闹钟3)内核调度优先级更的进程取代当前进程执行4) seconds秒钟之后闹钟超时了,内核发送SIGALRM信号给这个进程,处于未决状态 5)优先级更高的进程执行完了,内核要调度回这个进程执行。SIGALRM信号递达,执行处理函数之后再次进入内核 6返回这个进程的主控制流程,alarm(senconds)返回,调pause()挂起等待。

虽然alarm()函数下一句就是pause()函数,但是不能保证pause()会在alarm()后senconds之内调用它,如果在pause()之前屏蔽SIGALRM信号使它不能递达,在调用完毕后再解除屏蔽,但是它们之间也存在缝隙,但该信号仍然有可能被递达,要解决此问题,必须保证挂起等待信号与解除信号屏蔽为原子操作。因此使用sigsuspend()函数能很好的解决该问题。

函数原型:int sigsuspend(const sigset_t* sigmask)

wKioL1ctoyzj5UimAABuVQZevUs148.png

SIGCHILD信号:父进程调用waitpid()以非阻塞式等待子进程退出,子进程在退出后会给父进程发送SIGCHLD信号,主动通知父进程,使父进程回收其子进程资源。父进程可自定义信号处理函数回收子进程,这样父进程就可以每隔一段时间查看是否有子进程退出,其它时间处理自己的事情。wKioL1ctnJ3SuXlgAABm0RPCmF0815.pngwKioL1ctnLPj14XZAAAid_Tzunc450.png