2011-06-15 21 views
1

我有一个固定时间片的计时器1 s,setitimer(SIGPROF, &timeslice, NULL);。当我用一个线程运行进程时,sighandler会在一秒钟内调用一次。但是,如果进程中有两个或更多线程,则它们将是每秒两次sighandler调用。为什么会这样?或者如何拥有固定频率的定时器,而不依赖于正在运行的线程数量。关于sighandler的频率

附带可运行代码。打印输出显示sighandler被调用两次秒...(这不是当NUM_THREADS被改变为一个的情况下)

#include <sys/syscall.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/time.h>//itimerval 
#include <signal.h>//sigaction, SIGPROF... 
#include <pthread.h>//pthread_create()/join() 
#include <stdint.h>//uint32_t 
#include <stdlib.h>//exit() 
using namespace std; 

#ifndef NUM_THREADS 
#define NUM_THREADS 20 
#endif 

struct sigaction old_act_; 

int init_timer(int which, int musec) { 
    struct itimerval timeslice; 
    timeslice.it_interval.tv_sec = musec/1000000; 
    timeslice.it_interval.tv_usec = musec % 1000000; 
    timeslice.it_value.tv_sec = musec/1000000; 
    timeslice.it_value.tv_usec = musec % 1000000; 
    setitimer(which, &timeslice, NULL); 
    return 0; 
} 

void remove_timer(int which) 
{ 
    struct itimerval timeslice; 
    timeslice.it_interval.tv_sec = 0; 
    timeslice.it_interval.tv_usec = 0; 
    timeslice.it_value.tv_sec = 0; 
    timeslice.it_value.tv_usec = 0; 
    setitimer(which, &timeslice, NULL); 
} 

void install_handler(int signo, void(*handler)(int)) 
{ 
    sigset_t set; 
    struct sigaction act; 
    act.sa_handler = handler; 
    act.sa_flags = SA_RESTART; 
    sigaction(signo, &act, &old_act_); 
    sigemptyset(&set); 
    sigaddset(&set, signo); 
    sigprocmask(SIG_UNBLOCK, &set, NULL); 
    return; 
} 

void uninstall_handler(int signo, bool to_block_signal) 
{ 
    sigaction(signo, &old_act_, 0); 
    if(to_block_signal) 
    { 
     // block the signal 
     sigset_t set; 
     sigemptyset(&set); 
     sigaddset(&set, signo); 
     sigprocmask(SIG_BLOCK, &set, NULL); 
    } 
} 

void handler(int signo) 
{ 
    pid_t tid = syscall(SYS_gettid); 
    pid_t pid = syscall(SYS_getpid); 
    struct timeval now; 
    gettimeofday(&now, NULL); 
    printf("sig %d, pid %d, tid %d, time = %u.%06u\n", signo, static_cast<int>(pid), static_cast<int>(tid), static_cast<uint32_t>(now.tv_sec), static_cast<uint32_t>(now.tv_usec)); 
} 

void * threadRun(void * threadId) 
{ 
    for(uint64_t i = 0; i < 10000000000; i++) 
    { 
     //sleep(1); 
    } 
} 

int main() 
{ 
    int tick_musec = 1000000; 
    init_timer(ITIMER_PROF, tick_musec); 
    install_handler(SIGPROF, handler); 

    pthread_t threads[NUM_THREADS]; 
    long t; 
    for (t = 0; t < NUM_THREADS; t++) { 
     printf("In main: creating thread %ld\n", t); 
     if (pthread_create(&threads[t], NULL, threadRun, (void *) t)) { 
      printf("ERROR; return from pthread_create()\n"); 
      exit(-1); 
     } 
    } 
    void * status; 
    for (t = 0; t < NUM_THREADS; t++) { 
     if(pthread_join(threads[t], &status)) { 
      printf("ERROR; return from pthread_join()\n"); 
      exit(-1); 
     } 
     printf("Main: completed join with thread %ld having a status of %ld\n", t, (long) status); 
    } 

    remove_timer(ITIMER_PROF); 
    uninstall_handler(SIGPROF, true); 
    printf("Main: program completed. Exiting.\n"); 
    return 0; 
} 

以下是输出,具有4的双核处理器的计算机上运行时。

sig 27, pid 21542, tid 21544, core 6, time = 1308168237.023219 
sig 27, pid 21542, tid 21544, core 6, time = 1308168237.276228 
sig 27, pid 21542, tid 21549, core 6, time = 1308168237.528200 
sig 27, pid 21542, tid 21545, core 7, time = 1308168237.781441 
sig 27, pid 21542, tid 21551, core 6, time = 1308168238.037210 
sig 27, pid 21542, tid 21554, core 6, time = 1308168238.294218 
sig 27, pid 21542, tid 21551, core 6, time = 1308168238.951221 
sig 27, pid 21542, tid 21546, core 0, time = 1308168239.064665 
sig 27, pid 21542, tid 21561, core 1, time = 1308168239.335642 
sig 27, pid 21542, tid 21558, core 1, time = 1308168240.122650 
sig 27, pid 21542, tid 21555, core 6, time = 1308168240.148192 
sig 27, pid 21542, tid 21556, core 1, time = 1308168240.445638 
sig 27, pid 21542, tid 21543, core 7, time = 1308168240.702424 
sig 27, pid 21542, tid 21559, core 1, time = 1308168240.958635 
sig 27, pid 21542, tid 21555, core 6, time = 1308168241.210182 
sig 27, pid 21542, tid 21550, core 7, time = 1308168241.464426 
sig 27, pid 21542, tid 21553, core 0, time = 1308168241.725650 
sig 27, pid 21542, tid 21555, core 6, time = 1308168241.982178 
sig 27, pid 21542, tid 21547, core 7, time = 1308168242.234422 
sig 27, pid 21542, tid 21560, core 0, time = 1308168242.503647 
sig 27, pid 21542, tid 21546, core 0, time = 1308168242.766902 
sig 27, pid 21542, tid 21550, core 7, time = 1308168243.018414 
sig 27, pid 21542, tid 21552, core 0, time = 1308168243.270643 
sig 27, pid 21542, tid 21550, core 7, time = 1308168243.556412 

编辑:我已经有点解决了这个问题(也见@ n.m.的答案)。 SIGhandler在多处理器机器上运行更频繁的原因是SIGPROF是基于CPU时间而非实时发送的。 CPU时间可能比实时更长,例如CPU时间为2秒,可能是一个进程在1秒内有两个CPU在两个CPU上同时运行。

+0

在创建线程之后但在加入之前安装信号处理程序? – Kevin 2011-06-15 15:55:00

+1

你的CPU有多少核心?在有20个线程的四核机器上试试这个,或者禁用一个内核,看看会发生什么。 – 2011-06-15 16:30:12

+0

@Kevin重新安置sighandler安装不起作用... @n.m。该机器配有2个双核处理器。在20线程运行时不起作用 – Richard 2011-06-15 17:45:49

回答

0

您可以使用pthread_sigmask(...)在创建的线程中阻止SIGPROF。事实上,建议只有一个线程处理所有信号。

+0

好点。出于好奇,当有多个线程时,只有一个线程会收到信号。当有3个或更多线程时,处理程序以相同的速率运行。这就是我对这个程序感到困惑的原因。 – Richard 2011-06-15 17:50:39