东莞网推广网站建设,大型网站建设,做守望先锋h的网站,全国建筑资质查询系统可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑#xff0c;但无论如何设置#xff0c;程序都有可能在“解除信号屏蔽”与“挂起等待信号”这个两个操作间隙失去cpu资源。除非将这两步骤合并成一个“原子操作”。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应…可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑但无论如何设置程序都有可能在“解除信号屏蔽”与“挂起等待信号”这个两个操作间隙失去cpu资源。除非将这两步骤合并成一个“原子操作”。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应该使用sigsuspend替换pause。信号被解除屏蔽和进程挂起等待sigsuspend函数执行是同时进行的为原子操作不可分割。
int sigsuspend(const sigset_t *mask); //其作用与返回值都与pause函数一样-1EINTR。
sigsuspend函数调用期间进程信号屏蔽字由其参数mask指定该mask代替了PCB中的信号屏蔽字当函数执行完即返回-1后信号屏蔽字才会恢复作用。
可将某个信号如SIGALRM从临时信号屏蔽字mask中删除这样在调用sigsuspend时将解除对该信号的屏蔽然后挂起等待当sigsuspend返回时进程的信号屏蔽字恢复为原来的值。如果原来对该信号是屏蔽态sigsuspend函数返回后仍然屏蔽该信号。 在单核处理器中一条指令能完成的操作是原子的read、write、printf对应N多条汇编指令自然不是原子操作因为中断是发生指令之间的。多条指令之间基本都是通过lock来实现原子操作将这多条指令绑定为一个整体不可分割即原语。原语就是由若干条指令组成的用于完成一定功能的一个过程原语在执行过程中不允许被中断类似一条指令。原语在系统态下执行常驻内存。在内核中有许多原语如进程创建原语creat、挂起原语suspend、激活原语active、阻塞原语block和唤醒原语wakeup等。sigsuspend函数是一个系统调用系统调用都是一个原子操作sigsuspend系统调用实现进程的挂起和信号屏蔽的解除。
//mysleep函数的改进
#include unistd.h
#include signal.h
#include stdio.hvoid sig_alrm(int signo)
{/* nothing to do */
}unsigned int mysleep(unsigned int nsecs)
{struct sigaction newact, oldact;sigset_t newmask, oldmask, suspmask;unsigned int unslept;//1.为SIGALRM设置捕捉函数一个空函数newact.sa_handler sig_alrm;sigemptyset(newact.sa_mask);newact.sa_flags 0;sigaction(SIGALRM, newact, oldact);//2.设置阻塞信号集阻塞SIGALRM信号sigemptyset(newmask);sigaddset(newmask, SIGALRM);sigprocmask(SIG_BLOCK, newmask, oldmask); //信号屏蔽字mask//3.定时n秒到时后可以产生SIGALRM信号alarm(nsecs);/*4.构造一个调用sigsuspend临时有效的阻塞信号集* 在临时阻塞信号集里解除SIGALRM的阻塞*/suspmask oldmask;sigdelset(suspmask, SIGALRM);/*5.sigsuspend调用期间采用临时阻塞信号集suspmask替换原有阻塞信号集* 这个信号集中不包含SIGALRM信号,同时挂起等待* 当sigsuspend被信号唤醒返回时恢复原有的阻塞信号集*/sigsuspend(suspmask);unslept alarm(0);//6.恢复SIGALRM原有的处理动作呼应前面注释1思想sigaction(SIGALRM, oldact, NULL);//7.解除对SIGALRM的阻塞呼应前面注释2思想sigprocmask(SIG_SETMASK, oldmask, NULL);return(unslept);
}int main(void)
{while(1){mysleep(2);printf(Two seconds passed\n);}return 0;
}
时序竞态总结
竞态条件跟系统负载有很紧密的关系体现出信号的不可靠性。系统负载越严重信号不可靠性越强。不可靠由其实现原理所致。信号是通过软件方式实现(跟内核调度高度依赖延时性强)每次系统调用结束后或中断处理处理结束后需通过扫描PCB中的未决信号集来判断是否应处理某个信号。当系统负载过重时会出现时序混乱。
其本质原因就是进程随时都有可能会失去CPU失去CPU时间太长导致信号的处理与进程中主控程序的执行顺序发生了改变从而产生了不符合预期的结果出现错误。如上面的pause函数本应该在信号处理之前进行但是延时太长导致pause函数执行时信号提前被处理了。这都是因为信号的处理与主控程序的执行时序不一样产生了不一样的结果。这种错误只有程序员提前遇见主动规避。
这种意外情况只能在编写程序过程中提早预见主动规避而无法通过gdb程序调试等其他手段弥补。且由于该错误不具规律性后期捕捉和重现十分困难。