Linux进程的计时器和间隔计时器

比较常用的时间控制函数就是sleep();让我们当前的进程休眠指定的秒数。

系统中的每个进程都有一个私有的闹钟。这个闹钟很像一个计时器,可以设置在一定秒数后的闹钟。 时间一到,时钟就发送一个信号SIGALRM到进程。除非为SIGALRM设置了处理函数,否则信号将杀死这个进程。sleep函数由3个步骤组成:

     1.为SIGALRM设置一个处理函数;

     2.调用alarm(num_seconds);

     3.调用pause。

系统调用pause挂起进程直到信号到达。任何信号都可以唤醒进程,而非仅仅等待SIGALRM。

#include<stdio.h>
#include<signal.h>

int main()
{
	void wakeup(int);

	printf("about to sleep for 4 second\n");
	signal(SIGALRM, wakeup);  //  SIGALRM handler
	alarm(4);      //set clock       unsigned old = alarm(unsigned seconds);  old---> the rest seconds if there is a signal.
	pause();       // freeze here
	printf("Morning so soon ?\n");
}

void wakeup(int signum)
{
#ifndef SHHHH
	printf("Alarm received from kernel\n");
#endif
}
比sleep()更精确的延时是usleep(), 它可以精确到微秒。将当前进程挂起n微秒或者直到有一个不能被忽略的信号到达。


进程的三种计时器: 真实、进程和实用

1.ITIMER_REAL : 这个计时器计量真实的时间,无论进程在用户态还是核心态用了多少处理器时间它都记录。当这个计时器用尽,发送SIGALRM消息。

2.ITMER_VIRTUAL: 只有进程在用户态运行时才计时。当虚拟计时器用尽时,发送SIGVTALRM消息。这个时间30s比真实时间30s长。

3.ITIMER_PROF: 这个计时器在进程运行于用户态或由该进程调用而陷入核心态时计时。当这个计时器用尽,发送SIGPROF信号。


在程序中使用间隔计时器要稍微复杂一点,要选择计时器的类型,然后需要选择初始间隔和重复间隔,还要设置在struct itimerval中的值,然后将这个结构体通过调用setitimer传给计时器。为了读取计时器设置,使用getitimer。

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

int set_ticker(int n_msecs);

int main()
{
	void countdown(int );

	signal(SIGALRM, countdown);
	if(set_ticker(500) == -1)
		perror("set_ticker");
	else
		while(1)
		{
			pause();
		}
	return 0;
}

void countdown(int signum)
{
	static int num = 10;
	printf("%d ..", num--);
	fflush(stdout);
	if(num < 0) 
	{
		printf("DONE! \n");
		exit(0);
	}
	
}

int set_ticker(int n_msecs)
{
	struct itimerval new_timeset;
	long n_sec, n_usecs;

	n_sec = n_msecs / 1000;

	n_usecs = (n_msecs % 1000) * 1000L;

	new_timeset.it_interval.tv_sec = n_sec;  // set reload   设置初始间隔
	new_timeset.it_interval.tv_usec = n_usecs; //new ticker value

	new_timeset.it_value.tv_sec = n_sec;   //store this   设置重复间隔
	new_timeset.it_value.tv_usec = n_usecs;	//and this

	return setitimer(ITIMER_REAL, &new_timeset, NULL); 
      //#include<sys/time.h>  getitimer(int which, struct itimerval *val)
      //setitimer(int which, const struct itimerval* newval, struct itimerval *oldval);
      //which 指定哪种计时器  ITMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF. 
}


使用signal函数设置countdown来处理SIGALRM信号。然后通过set_ticker来设置微秒数。 set_ticker通过装载初始间隔和重复间隔设置间隔计时器。每个间隔是由两个值组成:秒数和微秒数,如同实数的整数部分和小数部分。计时器开始计时时,控制返回到main。

进入死循环后,调用pause。大约每500us,控制跳转到countdown函数。当num到0时,调用exit结束。

struct itimeal的结构如下:

struct itimerval
{
    struct timeval it_value;   //初始时间间隔,第一次发信号使用的时间,之后都不用了。
    struct timeval it_interval;  //重复时间间隔,第一次发信号之后使用的时间。
};

struct timeval
{
    time_t tv_sec;      //second
    suseconds_t tv_usec;    //microseconds
};


内核在每个时钟脉冲时,遍历所有的间隔计时器,使用这样的手段来管理每个进程的真实计时器。而其他两个计时器,在程序运行的特定时刻进行计时。通过这样的机制,来实现每个进程三个计时器的管理。我们通过setitimer系统调用,得到了更高的精度控制计时器,同时能够以固定的时间间隔发送信号。当然了,这个时间全可以随时修改的,在中断中改变一下,就可以了。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值