多线程中定时器的使用

发布者:大头玩家最新更新时间:2015-11-16 来源: eefocus关键字:多线程  定时器 手机看文章 扫描二维码
随时随地手机看文章
不管是在进程还是线程,很多时候我们都会使用一些定时器之类的功能,这里就定时器在多线程的使用说一下。首先在linux编程中定时器函数有alarm()和setitimer(),alarm()可以提供一个基于秒的定时功能,而setitimer可以提供一个基于微妙的定时功能。         alarm()原型:
         #i nclude
unsigned int alarm(unsigned int seconds);
这个函数在使用上很简单,第一次调用这个函数的时候是设置定时器的初值,下一次调用是重新设置这个值,并会返回上一次定时的剩余时间。
          setitimer()原型:
#i nclude
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;                 
       struct timeval it_value;                  
 };
 
struct timeval {
       long tv_sec;                       
       long tv_usec;                      
};
在结构体itimerval中it_value是定时器当前的值,it_interval是当it_value的为0后重新填充的值。而timeval结构体中的两个变量就简单了一个是秒一个是微秒。
上面是这两个定时函数的说明,这个函数使用本不是很难,可以说是很简单,但是碰到具体的应用的时候可能就遇到问题了,在多进程编程中使用一般不会碰到什么问题,这里说的这些问题主要体现在多线程编程中。比如下面这个程序
#i nclude
#i nclude
#i nclude
#i nclude
#i nclude
#i nclude
 
void sig_handler(int signo)
{
          alarm(2);
          printf("alarm signal ");
}
 
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 ");
                   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,线程中的信号屏蔽,函数的原型及相关函数为:
#i nclude
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);        
int sigaddset(sigset_t *set, int signum);
然后我们改造我们的程序为:
#i nclude
#i nclude
#i nclude
#i nclude
#i nclude
#i nclude
 
void sig_handler(int signo)
{
          alarm(2);
          printf("alarm signal ");
}
 
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 ");
                   sleep(10);
          }
          return 0;
}
这个时候我们就能够看到我们想要的结果了。
这里再附一个setitimer的使用范例
#i nclude
#i nclude
#i nclude
#i nclude
#i nclude
#i nclude
 
struct itimerval timerval;
void sig_handler(int signo)
{
          printf("alarm signal ");
}
 
 
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 ");
                   sleep(5);
          }

   

    
   return 0;

}
 
关键字:多线程  定时器 引用地址:多线程中定时器的使用

上一篇:嵌入式C、标准C、单片机C区别
下一篇:单片机一个IO口检测三种状态

推荐阅读最新更新时间:2024-03-16 14:39

使用STM32的单个普通定时器产生4路不同频率的方波
STM32的普通定时器有四路输出:TIMx_CH1、TIMx_CH2、TIMx_CH3和TIMx_CH4,可以使用输出比较的方法产生不同频率的方波输出,简单的方法是: 1)设置计数器为向上计数模式,将自动重装载寄存器设置为0xFFFF;这样计数器会循环计数。 2)每个定时器通道设置为输出比较模式,并设置比较匹配时对应的输出管脚翻转输出。 3)按照输出波形的半波周期计算出一个数值称作Half_Cyc。例如:定时器的时钟频率是72MHz,需要产生3456Hz的方波,则Half_Cyc = 72M/(3456*2) = 41667;如需要产生200kHz的方波,则Half_Cyc = 72M/(200k*2) = 180。
[单片机]
Stm32入门——Systick定时器
Systick定时器是什么? 从原理上来说,Systick定时器和开发板上的通用定时器没有区别。从功能上来说,Systick定时器主要是用来用来进行延时的(就是让CPU一直重复计数这件事),而通用或者高级定时器往往用来进行PWM输出、输入捕获等功能。至于为什么不用通用定时器或者高级定时器来完成延时功能,则是考虑到节省MCU的资源来做更重要的事。 Systick定时器相关寄存器 CTRL Systick控制和状态寄存器(存放使能位、中断位、时钟源选择位等) LOAD Systick自动重装载值寄存器 VAL Systick当前值寄存器 (这里插一句,建议大家在学习的时候直接对寄存器进行操作,不要用库函数,这样前期虽然会有困难,但
[单片机]
STM32的定时器(含中断)配置样例
1. 系统时钟配置 void RCC_Configuration(void) { ErrorStatus HSEStartUpStatus; RCC_DeInit(); RCC_HSEConfig(RCC_HSE_ON); HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (HSEStartUpStatus == SUCCESS) { RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB(HCLK)时钟为系统时钟 RCC_PCLK2Config(RCC_HCLK_Div1); //设置高速AHB时钟(APB2)为HCLK
[单片机]
TQ2440 学习笔记—— 22、系统时钟和定时器
系统时钟和定时器 启动MPLL 需要设置的寄存器: LOCKTIME (LOCK TIME COUNT)、MPLLCON(Main PLL Control)、CLKDIVN(clock divider control) 若Fout = 200MHz则, Fout = 2 *m * Fin / (p * 2 ^ s) = 2 * (92 + 8) * 12MHz / (3 * 2 ^ 2) = 200MHz m = 100, MDIV = 92 p = 3, PDIV = 2 s = 2, SDIV = 2 #define S3C2440_MPLL_200MHZ ((0x5c 12) | (0
[单片机]
TQ2440 学习笔记—— 22、系统时钟和<font color='red'>定时器</font>
技术文章—模拟电路正确的时序
许多模拟电路需要一种时钟信号,或者要求能在一定时间后执行某项任务。对于这样的应用,有各种各样适用的解决方案。对于简单的时序任务,可以使用标准的555电路。使用555电路和适当的外部组件,可以执行许多不同的任务。 然而,使用相当广泛的555定时器有一个缺点,就是设置不太精确。555定时器通过给外部电容充电和检测电压阈值来工作。这种电路很容易制作,但它的精度很大程度上取决于其电容的实际值。 晶体振荡器适用于精度要求较高的应用。它们的精度可能很高,但它们有一个缺点:可靠性。参与电气设备维修的人都知道,故障通常是由大型电解电容引起的。晶体振荡器是引起故障的第二大原因。 第三种测量时间长度或生成时钟信号的方法是使用一个简单的小型
[模拟电子]
技术文章—模拟电路正确的时序
【STM32H7教程】第35章 STM32H7的定时器应用之高精度单次延迟实现(支持TIM2,3,4和5)
35.1 初学者重要提示 学习本章节前,务必优先学习第32章,HAL库的几个常用API均作了讲解和举例。 STM32H7支持TIM1-TIM8,TIM12-TIM17共14个定时器,而中间的TIM9,TIM10,TIM11是不存在的,这点要注意。 在不需要任何补偿的情况下,误差可以做到正负1微秒以内。 TIM2和TIM5是32位定时器,而TIM3和TIM4是16位定时器。 35.2 定时器单次延迟驱动设计 单次定时器要实现1us的精度,可以直接将定时器时钟设置为1MHz,这样定时器每计数1次就是1us。对于16位定时器最大值就是0xFFFF微秒,而32位定时器就是0xFFFFFFFF微秒。 剩下的问题就是单次延迟时间到了可以及
[单片机]
【STM32H7教程】第35章 STM32H7的<font color='red'>定时器</font>应用之高精度单次延迟实现(支持TIM2,3,4和5)
avr定时器/计数器1 --TC1 --输入捕捉模式 (捕获外部事件模式)
T/C 的输入捕捉单元可用来捕获外部事件,并为其赋予时间标记以说明此时间的发生时刻。外部事件发生的触发信号由引脚ICP1 (PD6)输入,也可通过模拟比较器单元来实现。时间标记可用来计算频率、占空比及信号的其它特征,以及为事件创建日志。当引脚ICP1 上的逻辑电平( 事件) 发生了变化,或模拟比较器输出ACO 电平发生了变化,并且这个电平变化为边沿检测器所证实,输入捕捉即被激发:16 位的TCNT1 数据被拷贝到输入捕捉寄存器ICR1,同时输入捕捉标志位ICF1 置位。如果此时ICIE1 = 1,输入捕捉标志将产生输入捕捉中断。中断执行时ICF1 自动清零,或者也可通过软件在其对应的I/O 位置写入逻辑 1” 清零。读取ICR1
[单片机]
在Windows2000下用多线程实现1394串行总线通信
作者Email: zhaoyn2001@163.net 摘 要:基于Windows2000环境开发了1394主控机与1394设备机间进行串行总线通信的软硬件系统,其中采用了多线程技术,并利用临界区实现线程间共享资源的同步,从而有效地解决了串行通信中的实时响应问题,降低了数据的丢失率,提高了系统的可靠性。 关键词:多线程;1394总线;线程同步 1 引言 为了便于LS-1394物理层、链路层芯片设计课题的研究,我们采用FPGA和ISA总线开发了基于TI公司的TSB41AB3和TSB12LV01的ISA-1394的1394总线接口卡,并在Windows2000环境下开发了一套利用多线程技术实现1394主控机与1394设备机之
[工业控制]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved