Chinaunix首页 | 论坛 | 博客
  • 博客访问: 505250
  • 博文数量: 157
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 1608
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-16 09:30
文章存档

2010年(155)

2008年(2)

我的朋友

分类: LINUX

2010-05-05 13:39:09

Linux setitimer对于电脑使用的玩家的常用软件,然后我就学习及深入的研究Linux setitimer,在这里和大家一起探讨Linux setitimer的使用方法,希望对大家有用。Linux setitimer()为Linux的API,并非C语言的Standard Library,Linux setitimer()有两个功能,一是指定一段时间后,才执行某个function,二是每间格一段时间就执行某个function,以下程序demo如何使用Linux setitimer()。

  1. view plaincopy to clipboardprint?/*    
  2. Filename    : timer.cpp    
  3. Compiler    : gcc 4.1.0 on Fedora Core 5    
  4. Description : Linux setitimer() set the interval to run function    
  5. Synopsis    : #include <sys/time.h>    
  6. int Linux setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);    
  7. struct itimerval {    
  8. struct timerval it_interval;    
  9. struct timerval it_value;    
  10. };    
  11. struct timeval {    
  12. long tv_sec;    
  13. long tv_usec;    
  14. }  
  15. Release     : 11/25/2006    
  16. */     
  17. #include <stdio.h>    // for printf()     
  18. #include <unistd.h>   // for pause()     
  19. #include <signal.h>   // for signal()     
  20. #include <string.h>   // for memset()     
  21. #include <sys/time.h> // struct itimeral. Linux setitimer()     
  22. void printMsg(int);     
  23. int main() {     
  24. // Get system call result to determine successful or failed     
  25. int res = 0;     
  26. // Register printMsg to SIGALRM     
  27. signal(SIGALRM, printMsg);     
  28. struct itimerval tick;     
  29. // Initialize struct     
  30. memset(&tick, 0, sizeof(tick));     
  31. // Timeout to run function first time     
  32. tick.it_value.tv_sec = 1;  // sec     
  33. tick.it_value.tv_usec = 0; // micro sec.     
  34. // Interval time to run function     
  35. tick.it_interval.tv_sec = 1;     
  36. tick.it_interval.tv_usec = 0;     
  37. // Set timer, ITIMER_REAL : real-time to decrease timer,     
  38. //            send SIGALRM when timeout     
  39. res = Linux setitimer(ITIMER_REAL, &tick, NULL);     
  40. if (res) {     
  41. printf("Set timer failed!!\n");     
  42. }     
  43. // Always sleep to catch SIGALRM signal     
  44. while(1) {     
  45. pause();     
  46. }     
  47. return 0;       
  48. }     
  49. void printMsg(int num) {     
  50. printf("%s","Hello World!!\n");     
  51. }     
  52.  

当Linux setitimer()所执行的timer时间到了,会呼叫SIGALRM signal,所以在第30行用signal()将要执行的function指定给SIGALRM。 在第43行呼叫Linux setitimer()设定timer,但Linux setitimer()

第二个参数是sturct,负责设定timeout时间,所以第36行到第 40行设定此struct。itimerval.it_value设定第一次执行function所延迟的秒数, itimerval.it_interval设定以后每几秒执行function,所以若只想延迟一段时间执行function,只要设定 itimerval.it_value即可.

若要设定间格一段时间就执行function,则it_value和it_interval都要设定,否则 funtion的第一次无法执行,就别说以后的间隔执行了。 第36行和第39行的tv_sec为sec,第37行和40行为micro sec(0.001 sec)。 第43行的第一个参数ITIMER_REAL,表示以real-time方式减少timer,在timeout时会送出SIGALRM signal。

第三个参数会存放旧的timeout值,如果不需要的话,指定NULL即可。 第47 行的pause(),命令系统进入sleep状态,等待任何signal,一定要用while(1)无穷循环执行pause(),如此才能一直接收 SIGALRM signal以间隔执行function,若拿掉while(1),则function只会执行一次而已。

 

三,示例程序

实例一:信号发送及处理,看看函数sigaction是怎么使用的。
CODE

#include
#include
#include
void user_func(int,siginfo_t*,void*);

int main(int argc,char**argv)
{
struct sigaction act;
int sig;
sig=atoi(argv[1]);

sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO;
act.sa_sigaction=(void * )user_func;

if(sigaction(sig,&act,NULL) < 0)
{
printf("install sigal error\n");
}

while(1)
{
sleep(2);
printf("wait for the signal\n");
}
}
void user_func(int signum,siginfo_t *info,void *myact)
{
printf("receive signal %d\n\n\n", signum);
sleep(5);
}



在一终端执行cc -o act act.c
$./act 8&
[1] 992
$ wait for the signal
$

在另一终端执行

#kill -s 8 992


看看。。

$receive signal 8


实例二:信号阻塞及信号集操作

CODE

#include
#include
void user_func(int);
main()
{
sigset_t new_mask,old_mask,pending_mask;
struct sigaction act;

sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO;
act.sa_sigaction=(void*)user_func;

if(sigaction(SIGRTMIN+10,&act,NULL))
printf("install signal SIGRTMIN+10 error\n");

sigemptyset(&new_mask);
sigaddset(&new_mask,SIGRTMIN+10);

if(sigprocmask(SIG_BLOCK, &new_mask,&old_mask))
printf("block signal SIGRTMIN+10 error\n");

sleep(20);

printf("\n\nNow begin to get pending mask and unblock SIGRTMIN+10\n\n");
if(sigpending(&pending_mask)<0)
printf("get pending mask error\n");
if(sigismember(&pending_mask,SIGRTMIN+10))
printf("signal SIGRTMIN+10 is pending\n");

if(sigprocmask(SIG_SETMASK,&old_mask,NULL)<0)
printf("unblock signal error\n");

printf("signal unblocked ,ok ... ...\n\n\n");
}
void user_func(int signum)
{
printf("receive signal %d \n",signum);
}



$cc -o sus sus.c
$./sus&
[1] 997



another console
#kill -s 42 pid

看看...

$
Now begin to get pending mask and unblock SIGRTMIN+10

signal SIGRTMIN+10 is pending
receive signal 42
signal unblocked ,ok ... ...



[1]+ Exit 31 ./d
$



实例三:signal例子

CODE

#include
#include
#include
#define damo
void user_func(int no)
{
switch (no)
{
case 1:
printf("Get SIGHUP.\n");
break;
case 2:
printf("Get SIGINT\n");
break;
case 3:
printf("Get SIGQUIT \n");
break;
default:
printf("What wan yi a \n\n");
break;
}

}
int main()
{
printf("rocess id is %d\n ",getpid());

#ifdef damo
signal(SIGHUP, user_func);
signal(SIGINT, user_func);
signal(SIGQUIT, user_func);
signal(SIGBUS, user_func);
#else
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGBUS, SIG_DFL);
#endif

while(1)
;
}



这个就是signal的用法集中展示,也是我经常用的一个方法。说实话,sco太古老了。。俺只能用这个函数了。
测试时你可以把#define damo这个注释和不注释看看。深刻体会signal的用法。

BTW:signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);

等等忽略了这些信号后,可以让一个进程终端无关,即使你退出这个tty.当然kill信号还是不能屏蔽的。
这种方式多在守护进程中采用。

$ cc -o si si.c
$./si

Process id is 1501

在另一个tty上
#ps -ef
bank 1501 1465 51 04:07 pts/0 00:00:13 ./si
bank 1502 800 0 04:08 pts/1 00:00:00 ps -ef
#
注意观察这时候是1456
你把./si这个tty关掉。
这时候你再
#ps -ef看看
bank 1501 1 50 04:07 ? 00:00:59 ./si
bank 1503 800 0 04:09 pts/1 00:00:00 ps -ef
注意这个1和?,知道这个进程成啥了吧?成精拉。哈哈~~




实例四:pause函数
CODE

#include
#include
#include
void user_func()
{
printf("\n\nCatch a signal SIGINT \n");
}

int main()
{
printf ("pid = %d \n\n ",getpid());
signal(SIGINT, user_func);
pause();
printf("receive a signal \n\n");
}



在这个例子中,程序开始执行,就象进入了死循环一样,这是因为进程正在等待信号,
当我们按下Ctrl-C时,信号被捕捉,并且使得pause退出等待状态。


实例五:下面是关于setitimer调用的一个简单例子。

CODE

#include
#include
#include
#include

void user_func(int sig)
{
if ( sig == SIGALRM)
printf("Catch a signal SIGALRM \n");
else if ( sig == SIGVTALRM)
printf("Catch a signal SIGVTALRM\n");
}

int main()
{
struct itimerval value,ovalue,value2;

printf("rocess id is = %d \n",getpid());

signal(SIGALRM, user_func);
signal(SIGVTALRM, user_func);

value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;

setitimer(ITIMER_REAL, &value, &ovalue);

value2.it_value.tv_sec = 1;
value2.it_value.tv_usec = 500000;
value2.it_interval.tv_sec = 1;
value2.it_interval.tv_usec = 500000;

setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

while(1);
}





在该例子中,每隔1秒发出一个SIGALRM,每隔1.5秒发出一个SIGVTALRM信号:

结果如下
$ ./ti
Process id is = 1734
Catch a signal SIGALRM
Catch a signal SIGVTALRM
Catch a signal SIGALRM
Catch a signal SIGALRM
Catch a signal SIGVTALRM
Catch a signal SIGALRM
Catch a signal SIGVTALRM
Catch a signal SIGALRM
Catch a signal SIGALRM
Catch a signal SIGVTALRM
Catch a signal SIGALRM
Catch a signal SIGVTALRM
Catch a signal SIGALRM
Catch a signal SIGALRM
Catch a signal SIGVTALRM


ctrl+c中断。
....

开始喜欢setitimer函数了。。。

四,补充

不得不介绍一下setjmp和longjmp的作用。

在用信号的时候,我们看到多个地方要求进程在检查收到信号后,从原来的系统调用中直接返回,而不是等到该调用完成。
这种进程突然改变其上下文的情况,就是使用setjmp和longjmp的结果。setjmp将保存的上下文存入用户区,并继续在旧的
上下文中执行。这就是说,进程执行一个系统调用,当因为资源或其他原因要去睡眠时,内核为进程作了一次setjmp,如果
在睡眠中被信号唤醒,进程不能再进入睡眠时,内核为进程调用longjmp,该操作是内核为进程将原先setjmp调用保存在进程
用户区的上下文恢复成现在的上下文,这样就使得进程可以恢复等待资源前的状态,而且内核为setjmp返回1,使得进程知道
该次系统调用失败。这就是它们的作用。

有时间再man 一下waitpid吧。。都是很有用的。

五,后记

信号的处理从以前的使用到最终文档的成形,每次都感觉挺难,其实是挺偏的。毕竟,信号我们
一般接触的少,用的也少。其实大家不要谈信号色变,仔细研究一下,发现很有意思。
我接触的东西没有直接用信号处理一大堆东西的,都是简单的对信号的使用,所有例子比较少,很多
例子都是参考网络资料的。很多资料都是参考了网友的资料而成,尤其是郑彦兴网友。

阅读(2718) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~