开发者

On the frequency of sighandler

开发者 https://www.devze.com 2023-03-13 00:14 出处:网络
I have a timer with fixed timeslice 1s, setitimer(SIGPROF, &timeslice, NULL);. When I run the process with one thread, the sighandler is invoked once in one second. However, if there are two or mo

I have a timer with fixed timeslice 1s, setitimer(SIGPROF, &timeslice, NULL);. When I run the process with one thread, the sighandler is invoked once in one second. However, if there are two or more threads in the process, they will be two invocations of sighandler per second. Why is this the case? or how to have a timer with fixed frequency, independent of # of running threads.

The runnable code is attached. The printout shows sighandler is invoked twice a sec...(which is not the case when NUM_THREADS is changed to one)

#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>//itimerval
#include <signal.h>//s开发者_JAVA技巧igaction, 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;
}

Following is the output, when running on a machine with 4 dual-core processors.

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

Edit: I have kinda solved the problem (also see @n.m.'s answer). The reason sighandler runs more frequently on multi-processor machine is that SIGPROF is sent out based on CPU time not real time. CPU time can be bigger than real time, like if there is 2 sec in CPU time, it could be that one process has two threads running concurrently on 2 CPUs during 1 sec.


You can use pthread_sigmask(...) to block the SIGPROF in the created threads. In fact, it's recommended to have only one thread handling all the signals.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号