linux定时器的使用

linux 定时器使用

1 简介

有三种可以使用

  • alarm定时器,在要求不太精确的情况可以使用这种
  • 用settimer来设置定时器
  • 使用select作为周期性的定时器

2 alarm定时器

//参考如下链接
https://blog.csdn.net/vanturman/article/details/84131324

2.1 alarm函数定义

  • 引用头文件:#include <unistd.h>;
  • 函数标准式:unsigned int alarm(unsigned int seconds);
  • 功能与作用:alarm()函数的主要功能是设置信号传送闹钟,即用来设置信号SIGALRM在经过参数seconds秒数后发送给目前的进程。如果未设置信号SIGALARM的处理函数,那么alarm()默认处理终止进程。
  • 函数返回值:
    成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。注意,alarm调用前就已经返回了。
    出错:-1

2.2 alarm测试例1

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
 
void handler(int sig) {
    printf("this is handler function!\n");
    exit(0);
}
 
int main(int argc, char **argv) {
    signal(SIGALRM, handler);
    alarm(1);
    sleep(5);
    printf("hello world!\n");
    return 0;
}

在这里插入图片描述
程序分析:在文件alarm_test_1.c中,定义了一个时钟alarm(5),它的作用是让信号SIGALRM在经过5秒后传送给目前main()所在进程;接着又定义了sleep(1),它的作用是让执行挂起1秒的时间。所以当main()程序挂起1秒钟时,signal函数调用SIGALRM信号的处理函数sig_alarm,并且sig_alarm输出并执行exit(0)使得程序直接退出。因此,printf(“hello world!\n”)语句是没有被执行的。

2.3 alarm 测试例2

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
 
void handler(int sig) {
    printf("this is handler function!\n");
    exit(0);
}
 
int main(int argc, char **argv) {
    signal(SIGALRM, handler);
    alarm(5);
    sleep(1);
    printf("hello world!\n");
    return 0;
}

在这里插入图片描述
程序分析:与上一个测试不同的是,在本测试代码中延时函数为sleep(1),即执行挂起5秒的时间。所以当main()程序挂起1秒钟时,由于还没到达设置的闹钟5秒,那么main就执行下面的printf(“hello world!\n”)语句;紧接着又执行下面的return 0语句,从而直接退出程序。因此,本次输出的内容为:hello world!。

2.4 alarm测试例3

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
 
void handler(int sig) {
    printf("hello, this is signal %d\n", sig);
}
 
int main(int argc, char **argv) {
    signal(SIGALRM, handler);
    alarm(5);
    for (int i = 1; i < 7; ++i) {
        sleep(1);
        printf("sleep %d secs.\n", i);
    }
    return 0;    
}

在这里插入图片描述
程序分析:在文件alarm_test_2.cpp中,定义时钟alarm(5),而main()函数中主要是一个for循环输出语句。当main函数执行到i=5时,for循环先执行sleep(1)语句,此时已经到达闹钟时间5秒,因此会把信号SIGALRM传送给当前main()函数进程;接着调用SIGALRM信号的处理函数handler,从而输出"hello",然后for循环中输出这个点printf(“sleep %d secs.\n”, i)语句输出"sleep 5 …";最后for循环执行i=6,输出"sleep 6",最终结束整个程序。

以上三个程序都只包含一个alarm()闹钟函数,下面两个程序包含两个alarm()。并且为了更为真切的观察包含alarm()闹钟函数的程序的执行过程,程序通过调用系统打印输出当前时间,通过时间差来进一步理解。

2.5 alarm 测试例4

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
 
void handler(int sig) {
    system("date");
    return;
}
 
int main(int argc, char **argv) {
    signal(SIGALRM, handler);
    system("date");
    alarm(10);
    sleep(5);
    printf("%d\n", alarm(1));
    pause();
    return 0;
}

程序分析:在alarm_test_3.cpp的main()函数中,先设置了一个闹钟函数alarm(10),即在10秒时将SIGALRM信号传送送给当前进程;然后又定义了一个延时函数sleep(5),接着又定义了一个闹钟函数alarm(1),它的作用是清除前面设置的闹钟alarm(10)并返回剩余的时间10-5=5秒。所以,程序先执行system(“date”)语句输出当前时间;然后进程休眠5秒后,程序执行输出语句printf("%d\n",alarm(1)),由于alarm(1)先返回5秒,即打印输出5;接着程序执行pause()函数,使当前进程处于挂起状态,直到捕捉到一个信号;当再过1秒后,SIGALARM信号的处理函数sig_alrm执行system(“date”)语句输出当前时间;最后pause终止进程。因此,整个程序执行的时间为5+1=6秒。

3 利用settimer做定时

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>

int count[4] = {0};
void set_timer()
{
	//设置为1秒钟调用一次
	struct itimerval itv, oldtv;
	itv.it_interval.tv_sec = 1;
	itv.it_interval.tv_usec = 0;
	itv.it_value.tv_sec = 1;
	itv.it_value.tv_usec = 0;

	setitimer(ITIMER_REAL, &itv, &oldtv);
}

void sigalrm_handler(int sig)
{
	count[0]++;
	count[1]++;
	count[2]++;
	count[3]++;
	//timer_30s++;
	//printf("timer signal.. %d\n", count);
}

void * fpga_thread(void *arg)
{
	char port_no = *(char*)arg;
	
	while(1)
	{
		if(count[port_no] == 5)
		{
			printf("timer port_no\r\n",port_no);
		}
	   //实际使用中可以设置多个定时器,例如 5秒定时,处理。如上。
	   //例  30s定时
	   // if timer_30s == 30
	   //       handle code is here.
	   //       timer_30s = 0;	
		usleep(1000); //延迟1ms为了让出cpu。
	}
}

int main()
{
	pthread_t th;
	int i;
	//给定时器设置了句柄函数,定时器超时,会调用该函数
	signal(SIGALRM, sigalrm_handler);
	//设置定时器调用该句柄函数的间隔时长
	set_timer();
	//常见4个线程
	for(i=0;i<4;i++)
	{
		pthread_create(&th,NULL,fpga_thread,i);
	}
	
	while(1)
	{
		sleep(1);  //同样是为了让出cpu
	}
}

gcc -o tests tests.c -lpthread
程序分析:
程序中只起了一个定时器,linux应该只能支持这一个定时器,要在多个线程中使用,就要设置多个,每个线程中使用不同的,例如上边程序中count[] 数组四个分别模拟4个timer,相当于每个线程使用一个timer,各timer之间独立,不互相打扰。

4 select 做定时

4.1 首先看用sleep做延时

main()
{
    while(1)
    {
        //业务处理代码
        if(timer >=60)
        {
             //每60s处理一次
             timer = 0;
        }
        sleep(1);
        timer++
    }
}

4.2 用select 也可以达到同样的效果

上边代码示例,因为业务处理代码很有可能也有一些延时,这样会造成60s是不准的,实际的时间长度会超过60s。如果使用select,能让时间准确一些。(标注:感觉也不一定)

main()
{
    struct timeval tv;
    tv.tv_sec= 1;
    tv.tv_usec= 0;
    int err;
    do{
		err = select(0,NULL,NULL,NULL,&tv);
		if(timer == 60){
			此处写业务处理代码,能保证60s的业务处理时间是准确的。
		}
		timer++
    }while(err<0)
}

按我当前遇到的问题,使用settimer和select都可以,但似乎select用在我的程序里做改造更加的方便。

由于时间紧,文章写的比较简略,以后在做完善。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值