日期:2014-05-16  浏览次数:20795 次

一段代码,在单核/多核环境下运行,结果不一样,求高手解释!
我测试linux(centos5.6)上面的信号是否是安全的,不会丢失(哪怕cpu占用率100%的时候)。

发现一个奇怪的现象。下面一小段代码的主要功能是,创建两个计时器,定时输出一段字符串,其中第二个计时器做了一些消耗cpu的计算。我是在windows xp sp3的vbox 4.1下面安装的linux。

我发现单cpu机器运行和多cpu机器运行,结果是不一样的,这到底是为什么?
代码:
C/C++ code

#include<signal.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<time.h> 
#include<unistd.h> 
int count1=0,count2=0; 
void handler1(int sig,siginfo_t*,void*){ 
     if(sig==SIGRTMIN){printf("Timer 1s:%d\n",++count1);} 
} 
void handler2(int sig,siginfo_t*,void*){ 
     if(sig==SIGRTMIN+1){printf("              Timer 2s:%d\n",++count2);} 
     for(int i=0;i<2000000000;++i){ 
         int j=i+2; 
         int k=j*j; 
     } 
} 
timer_t createTimer(int sig, double secs){ 
     sigevent sev; 
     timer_t timerid; 
     sev.sigev_notify=SIGEV_SIGNAL; 
     sev.sigev_signo =sig; 
     sev.sigev_value.sival_ptr=&timerid; 
     if(timer_create(CLOCK_REALTIME,&sev,&timerid)==-1)return 0; 
      
     long freq_nanosecs=(long)secs*1000000000; 
     itimerspec its; 
     its.it_value.tv_sec    =freq_nanosecs/1000000000; 
     its.it_value.tv_nsec   =freq_nanosecs%1000000000; 
     its.it_interval.tv_sec =its.it_value.tv_sec; 
     its.it_interval.tv_nsec=its.it_value.tv_nsec; 
  
     if(timer_settime(timerid,0,&its,NULL)==-1)return 0; 
     return timerid; 
} 
int main(void){ 
     struct sigaction sa; 
     sa.sa_flags=SA_SIGINFO; 
     sa.sa_sigaction=handler1; 
     sigemptyset(&sa.sa_mask); 
     if(sigaction(SIGRTMIN,&sa,NULL)==-1)return 1; 
     sa.sa_sigaction=handler2; 
     if(sigaction(SIGRTMIN+1,&sa,NULL)==-1)return 2; 
      
     createTimer(SIGRTMIN,  1); 
     createTimer(SIGRTMIN+1,2); 
     int left=10; 
     do{left=sleep(left);}while(left>0); 
     return 0; 
} 


运行结果和发现: 
(1)当第二个计时器没有消耗cpu的计算时(我注释掉for循环),程序的结果如我的预期: 
Timer 1s:1 
Timer 1s:2 
  Timer 2s:1 
Timer 1s:3 
Timer 1s:4 
  Timer 2s:2 
Timer 1s:5 
Timer 1s:6 
  Timer 2s:3 
Timer 1s:7 
Timer 1s:8 
  Timer 2s:4 
Timer 1s:9 
Timer 1s:10 
  Timer 2s:5 
  
(2)当for循环存在的时候,如果此时的运行环境是1个cpu,那么结果仍然是正确的。不过,每次打印之间间隔的时间变得很长了,总运行时间也远不止10s。 
(3)当for循环存在的时候,如果此时的运行环境是多个cpu(vbox可以更改cpu个数),那么结果就是非常奇怪的: 
Timer 1s:1 
Timer 1s:2 
  Timer 2s:1 
  Timer 2s:2 
  Timer 2s:3 
  Timer 2s:4 
  Timer 2s:5 
  Timer 2s:6 
  Timer 2s:7 
  Timer 2s:8 
  Timer 2s:9 
  
(4)我的初步分析: 
当机器只有一个cpu的时候,OS和进程轮流使用时间片。两个timer轮流使用cpu时间,当第二个timer在消耗cpu的时候,期间OS并没有给两个计时器增加时间,也不会通知两个计时器的事件。 
  
但是多cpu的时候,OS占用一个cpu,不断的给两个计时器计时。所以第二个timer不断的被OS提醒运行,占用了进程的所有的cpu时间,而第一个timer的计时信号则不断的被OS插入提醒列表,但是没有被响应。 
  
这也就是说明linux的行为,在cpu数量发生变化的时候,是会改变的?

------解决方案--------------------
在aix环境下试验了一下,行为与lz的第3种情况类似

不仅第一个timer没有执行,连sleep也没有执行
看样子是全部的时间都给了timer2
可能与timer2中的for循环的执行耗时超过2s有关

信号处理程序的优先级相对较高,所以sleep得不到调度