多線程中定時器的使用

不管是在進程還是線程,很多時候我們都會使用一些定時器之類的功能,這裏就定時器在多線程的使用說一下。首先在linux編程中定時器函數有alarm()和setitimer(),alarm()可以提供一個基於秒的定時功能,而setitimer可以提供一個基於微妙的定時功能。

alarm()原型:
        #include <unistd.h>
        unsigned int alarm(unsigned int seconds);

這個函數在使用上很簡單,第一次調用這個函數的時候是設置定時器的初值,下一次調用是重新設置這個值,並會返回上一次定時的剩餘時間。

setitimer()原型:
        #include <sys/time.h>
        int setitimer(int which, const struct itimerval *value,struct itimerval *ovalue);

這個函數使用起來稍微有點說法,首先是第一個參數which的值,這個參數設置timer的計時策略,which有三種狀態分別是:

ITIMER_REAL:使用系統時間來計數,時間爲0時發出SIGALRM信號,這種定時能夠得到一個精準的定時,當然這個定時是相對的,因爲到了微秒級別我們的處理器本身就不夠精確。

ITIMER_VIRTUAL:使用進程時間也就是進程分配到的時間片的時間來計數,時間爲0是發出SIGVTALRM信號,這種定時顯然不夠準確,因爲系統給進程分配時間片不由我們控制。

ITIMER_PROF:上面兩種情況都能夠觸發

第二個參數參數value涉及到兩個結構體:

struct itimerval {
                struct timeval it_interval;        /* next value */
                struct timeval it_value;        /* current value */
        };

struct timeval {
                long tv_sec;        /* seconds */
                long tv_usec;        /* microseconds */
        };

在結構體itimerval中it_value是定時器當前的值,it_interval是當it_value的爲0後重新填充的值。而timeval結構體中的兩個變量就簡單了一個是秒一個是微秒。

上面是這兩個定時函數的說明,這個函數使用本不是很難,可以說是很簡單,但是碰到具體的應用的時候可能就遇到問題了,在多進程編程中使用一般不會碰到什麼問題,這裏說的這些問題主要體現在多線程編程中。比如下面這個程序:

#include <pthread.h>
        #include <signal.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/time.h>
void sig_handler(int signo)
        {
        alarm(2);
        printf("alarm signal\n");
        }
void *pthread_func()
        {
        alarm(2);
        while(1)
        {
                pause();
        }
        }
int main(int argc, char **argv)
        {
        pthread_t tid;
        int retval;
signal(SIGALRM, sig_handler);

        if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
        {
                perror("pthread_create");
                exit(-1);
        }
while(1)
        {
                printf("main thread\n");
                sleep(10);
        }
        return 0;
        }


        這個程序的理想結果是:
        main thread
        alarm signal
        alarm signal
        alarm signal
        alarm signal
        alarm signal
        main thread
        可事實上並不是這樣的,它的結果是:
        main pthread
        alarm signal
        main pthread
        alarm signal
        main pthread

爲什麼會出現這種情況呢?是因爲發送給工作線程的信號中斷的主線程的sleep,並且這個中情況隻影響主線程而不會影響到其他的工作線程。我們怎麼才能解決這種問題呢,最簡單的方法是修改這個程序,修改這個線程主線程使用alarm,工作線程使用sleep。這樣就能夠達到我們的要求,但是有時候有不能簡單的這樣操作。所以我們就需要進一步的修改我們的程序。在這裏我第一個想到的是使用signal(SIGALRM, SIG_IGN),可是這個是設置整個進程對這個信號的響應方式,經過測試也確實不能完成我期望的功能,那麼怎麼辦呢?有這樣一個函數pthread_sigmask,線程中的信號屏蔽,函數的原型及相關函數爲:

#include <signal.h>
        int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
        函數中第一個參數how有三個值SIG_BLOCK、SIG_SETMASK和SIG_UNBLOCK這裏我們是用第二個值SIG_SETMASK
        int sigemptyset(sigset_t *set); /*清除信號集合set*/
        int sigaddset(sigset_t *set, int signum); /*添加信號signum到信號集set中*/
        然後我們改造我們的程序爲:
       

 #include <pthread.h>
        #include <signal.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/time.h>
void sig_handler(int signo)
        {
        alarm(2);
        printf("alarm signal\n");
        }
void *pthread_func()
        {
        alarm(2);
        while(1)
        {
        pause();
        }
        }
int main(int argc, char **argv)
        {
        pthread_t tid, tid_1;
        int retval;
signal(SIGALRM, sig_handler);

        if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
        {
                perror("pthread_create");
                exit(-1);
        }

        sigset_t sigset;
        sigemptyset(&sigset);
        sigaddset(&sigset, SIGALRM);
        pthread_sigmask(SIG_SETMASK,&sigset,NULL);
while(1)
        {
                printf("main pthread\n");
                sleep(10);
        }
        return 0;
        }

這個時候我們就能夠看到我們想要的結果了。

這裏再附一個setitimer的使用範例:

#include <pthread.h>
        #include <signal.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/time.h>
struct itimerval timerval;
        void sig_handler(int signo)
        {
        printf("alarm signal\n");
        }
void *pthread_func()
        {
setitimer(ITIMER_REAL, &timerval, NULL);
        while(1)
        {
                pause();
        }
        }
int main(int argc, char **argv)
        {
        pthread_t tid;
        int retval;
        timerval.it_interval.tv_sec = 2;
        timerval.it_interval.tv_usec = 0;
        timerval.it_value.tv_sec = 2;
        timerval.it_value.tv_usec = 0;
signal(SIGALRM, sig_handler);

        if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
        {
                perror("pthread_create");
                exit(-1);
        }
sigset_t sigset;
        sigemptyset(&sigset);
        sigaddset(&sigset, SIGALRM);
        pthread_sigmask(SIG_SETMASK,&sigset,NULL);
while(1)
        {
                printf("main thread\n");
                sleep(5);
        }
        return 0;
        }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章