linux 多线程中定时器的使用

在开发linux mjpg-streamer程序的时候,使用signal,奇怪的是程序竟然退出了。后来读了曹老师的文章,才解决了这个问题。

所以收录到自己的博客里。呵呵

多线程中定时器的使用

        

        不管是在进程还是线程,很多时候我们都会使用一些定时器之类的功能,这里就定时器在多线程的使用说一下。首先在linux编程中定时器函数有alarm()setitimer(),alarm()可以提供一个基于秒的定时功能,而setitimer可以提供一个基于微妙的定时功能。

         alarm()原型:

         #include

unsigned int alarm(unsigned int seconds);

这个函数在使用上很简单,第一次调用这个函数的时候是设置定时器的初值,下一次调用是重新设置这个值,并会返回上一次定时的剩余时间。

          setitimer()原型:

#include

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 */

};

在结构体itimervalit_value是定时器当前的值,it_interval是当it_value的为0后重新填充的值。而timeval结构体中的两个变量就简单了一个是秒一个是微秒。

上面是这两个定时函数的说明,这个函数使用本不是很难,可以说是很简单,但是碰到具体的应用的时候可能就遇到问题了,在多进程编程中使用一般不会碰到什么问题,这里说的这些问题主要体现在多线程编程中。比如下面这个程序

#include

#include

#include

#include

#include

#include

 

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

int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);

函数中第一个参数how有三个值SIG_BLOCKSIG_SETMASKSIG_UNBLOCK这里我们是用第二个值SIG_SETMASK

int sigemptyset(sigset_t *set);         /*清除信号集合set*/

int sigaddset(sigset_t *set, int signum); /*添加信号signum到信号集set*/

然后我们改造我们的程序为:

#include

#include

#include

#include

#include

#include

 

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

#include

#include

#include

#include

#include

 

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;

}

 

个人的一些理解,有问题希望和大家交流!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux,可以使用多线程来实现定时器功能。一种常见的方法是使用`timer_create`函数创建一个定时器对象,然后使用`timer_settime`函数来设置定时器的触发时间和间隔。在定时器触发时,系统会发送一个信号给指定的线程,该线程可以在信号处理函数执行相应的操作。 以下是一个简单的示例代码,演示了如何在多线程使用定时器: ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <pthread.h> #include <time.h> #define TIMER_INTERVAL_SEC 1 void timer_handler(int sig) { // 定时器触发时执行的操作 printf("Timer expired\n"); } void* thread_func(void* arg) { // 创建定时器 timer_t timer; struct sigevent sev; struct itimerspec its; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &timer; timer_create(CLOCK_REALTIME, &sev, &timer); // 设置定时器的触发时间和间隔 its.it_value.tv_sec = TIMER_INTERVAL_SEC; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = TIMER_INTERVAL_SEC; its.it_interval.tv_nsec = 0; timer_settime(timer, 0, &its, NULL); // 等待定时器触发 while (1) { sleep(1); } return NULL; } int main() { pthread_t thread; // 创建线程 pthread_create(&thread, NULL, thread_func, NULL); // 等待线程结束 pthread_join(thread, NULL); return 0; } ``` 在上面的代码,主线程创建了一个子线程,并在子线程创建了一个定时器定时器的触发时间被设置为1秒,当定时器触发时,会执行`timer_handler`函数的操作。主线程使用`pthread_join`函数等待子线程结束。 请注意,上述示例的代码仅供参考,并未处理一些潜在的错误情况。在实际应用,您可能需要添加适当的错误处理和线程同步机制以确保程序的正确性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值