目录
setitimer函数
设置定时器
(
闹钟
)
。可代替
alarm
函数。
精度微秒
us
,
可以实现周期定时
int setitimer ( int which , const struct itimerval * new_value , struct itimerval * old_value );// 返回值:成功 : 0 ;失败 : - 1 , 设置 errno .// 参数 1: which: 指定定时方式自然定时 : ITIMER_REAL 计算自然时间。虚拟空间计时 ( 用户空间 ): ITIMER_VIRTUAL 只计算进程占用 cpu 的时间。运行时计时 ( 用户 + 内核 ): ITIMER_PROF 计算占用 cpu 及执行系统调用的时间。// 参数 2 : new_value: 定时秒数struct itimerval{struct timeval{time_t tv_sec ; /* seconds */suseconds_t tv_usec : /* microseconds */} it_interval ;struct timeval{time_t tv_sec ; /* seconds */suseconds_t tv_usec : /* microseconds */} it_value ;}// 参数 3 : old_value: 传出参数,上次定时剩余时间old_value 參数,它是用来存储上一次 setitimer 调用时设置的 new_value 值。通常使用不上,设置为 NULL 。
提示:
it interval:
用来设定两次定时任务之间间隔的时间。
it value:用于设定延时时间。
settimer
工作机制是,先对
it_value
倒计时,当
it_value
倒计时为零时触发信号。然后触发
it_interval
倒计时。倒计时为零时,触发信号,处理信号;同时
it_interval
再次进行倒计时,一直这样循环下去。
注:两个参数都设置为0,即清0操作。
练习
:
使用
setitimer
函数实现
alarm
函数,重复计算机
1
秒数数程序。
[ setitimer. c ]
#include<stdio.h>
#include<signal.h>
#include<sys/time.h>
#include<stdlib.h>
void myfunc(int signo)
{
printf("hello world\n");
exit(1);
}
int main(void)
{
// struct itimerval 结构体原型,代码后面有解释
struct itimerval newit;
signal(SIGALRM,myfunc); //注册SIGALRM信号的捕捉处理函数。
newit.it_value.tv_sec = 1;
newit.it_value.tv_usec = 0;
newit.it_interval.tv_sec = 2;
newit.it_interval.tv_usec = 0;
if(setitimer(ITIMER_REAL, &newit, NULL) == -1)
{
perror("setitimer error");
return -1;
}
int i=0;
while(1)
{
i++;
printf("i=%d\n",i);
}
return 0;
}
信号集操作函数
1.信号集设定
内核通过读取未决信号集来判断信号是否被处理。
信号屏蔽字
mask
可以影响未决信号集。而我们可以在应用程序中自定义set
来改变
mask.
已达到屏蔽指定信号的目的。
信号集操作函数
// 清空 setint sigemptyset ( sigset_t * set );// 置 1 setint sigfillset ( sigset_t * set );// 把某个信号加入到 setint sigaddset ( sigset_t * set , int signum );// 把某个信号从 set 中移除int sigdelset ( sigset_t * set , int signum );// 查看某个信号,是否在 set 中int sigismember ( const sigset_t * set , int signum );
2.igprocmask函数
用来设置屏蔽信号、解除屏蔽。其本质,读取或修改进程的信号屏蔽字
(PCB
中
)
。
严格注意,屏蔽信号
:
只是将信号处理延后执行
(
延至解除屏蔽
),
而忽略表示将信号丢处理。
int sigprocmask ( int how , const sigset_t * set , sigset_t * oldset );返回值:成功 : 0 ;失败 : - 1 , 设置 errno参数 1 how : SIG_BLOCK ( 设置阻塞 ) , SIG_UNBLOCK ( 取消阻塞 ), SIG_SETMASK ( 自定义 set )set : 自定义 setoldset:旧有的 mask
3.sigpending函数
读取当前进程的未决信号集
int sigpending ( sigset_t * set )返回值:成功 : 0 ;失败 : - 1 , 设置 errno参数: set 传出未决信号集
例程:使用自定义set,屏蔽ctrl+c 2号信号,读取当前进程信号集打印至屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void print_set(sigset_t *set)
{
int i;
for(i=1;i<32;i++)
{
if(sigismember(set,i))
{
putchar('1');
}
else
{
putchar('0');
}
}
printf("\n");
}
int main(int argc, char *argv[] )
{
sigset_t set,oldset,pendset;
sigemptyset(&set);
sigaddset(&set, SIGINT);//屏蔽ctrl+c 2号信号
int ret=sigprocmask(SIG_BLOCK,&set,&oldset);
if(ret==-1)
{
sys_err("sigprocmask err");
}
while(1)
{
ret=sigpending(&pendset);
if(ret==-1)
{
sys_err("sigprocmask err");
}
print_set(&pendset);
sleep(1);
}
return 0;
}
信号捕捉
1.signal函数
==
注册
==
一个信号捕捉函数
:
typedef void ( * sighandler_t )( int );sighandler_t signal ( int signum , sighandler_t handler );
该函数由
ANSI
定义。由于历史原因在不同版本的
Unix
和不同版本的
Linux
中可能有不同的行为。因此应该尽量避免使用它,取而代之使用sigaction
函数。
例程:捕捉信号ctrl+c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void sig_cath(int signum)
{
printf("catch you ! %d\n",signum);
}
int main(int argc, char *argv[] )
{
signal(SIGINT,sig_cath);
while(1);
return 0;
}
2.sigaction函数
修改信号处理动作
(
通常在
Linux
用其来注册一个信号的捕捉函数
)
。
int sigaction ( int signum , const struct sigaction * act , struct sigaction* oldact );返回值:成功 : 1失败 : - 1 , 设置 errno参数act : 传入参数,新的处理方式。oldact : 传出参数,旧的处理方式。
struct sigaction{void ( * sa_handler )( int );void ( * sa_sigaction )( int , siginfo_t * , void * );sigset_t sa_mask ;int sa_flags ;void ( * sa_restorer )( void );};sa_restorer : 该元素是过时的,不应该使用, POSIX . 1 标准将不指定该元素。 ( 弃用 )sa_sigaction : 当 sa_flags 被指定为 SA_SIGINFO 标志时 , 使用该信号处理程序。 ( 很少使用 )重点掌握sa_handler : 指定信号捕捉后的处理函数名 ( 即注册函数 ) 。也可赋值为 SIG_IGN 表忽略或 SIG_DFL 表执行默认动作。sa_mask : 调用信号处理函数时,所要屏蔽的信号集合 ( 信号屏蔽子 ) 。往意,仅在处理函数被调用期间屏蔽生效,是临时性设置。sa_flags : 通常设置为 0 . 表使用默认属性,捕捉函数执行期间,屏蔽同一信号再次过来调用捕捉。
例程:捕捉信号ctrl+c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void sig_cath(int signum)
{
printf("catch you ! %d\n",signum);
}
int main(int argc, char *argv[] )
{
struct sigaction act, oldact;
act.sa_handler = sig_cath; // 设置回调 信号捕捉函数
sigemptyset(&(act.sa_mask)); // 情况sa_mask屏蔽字 只在捕捉函数执行期间有效
act.sa_flags = 0; // 使用默认值
int ret = sigaction(SIGINT, &act, &oldact);
if (ret == -1)
{
sys_err("sigaction error ");
}
while (1);
return 0;
}
●
信号捕捉特性。
1.
进程正常运行时, 默认
PCB
中有一个信号屏蔽字,假定为※,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由※来指定。而是用sa_mask
来指定。调用完信号处理函数,再恢复为※
2.XXX
信号捕捉函数执行期间,
XXX
信号自动被屏蔽(
sa_flags=0
)。
3.
阻塞的常规信号不支持排队, 产生多次只记录一次。
(
后
32
个实时信号支持排队
)
。
SIGCHLD信号
1.SIGCHLD的产生条件
子进程终止时子进程接收到 SIGSTOP 信号停止时。子进程处在停止态,接受到 SIGCONT 后唤醒时。
2.借助SIGCHLD信号回收子进程
子进程结束运行,其父进程会收到
SIGCHLD
信号。该信号的默认处理动作是忽略。
可以捕捉该信号,在捕捉函数中完成子进程状态的回收。
例程:创建10个子进程,利用SIGCHLD信号进行回收
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void catch_child(int signum)
{
pid_t wpid;
while((wpid=wait(NULL))!=-1)
{
printf("-----------catch child id %d\n",wpid);
}
}
int main()
{
pid_t pid;
int i;
for(i=0;i<15;i++)
{
if((pid=fork())==0)
{
break;
}
}
if(i==15)
{
struct sigaction act;
act.sa_handler=catch_child;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGCHLD,&act,NULL);
printf("I am parent process! pid=%d\n",getpid());
while(1)
{
;//父进程其他任务
}
}
else
{
printf("I am %dth child process! pid=%d\n",i+1,getpid());
sleep(1);//子进程的业务功能
}
return 0;
}