linux提供的信号机制是一种进程间异步的通信机制,在实现上是一种软中断。
信号可以导致一个正在运行的进程被另一个进程异步进程中断,转而处理某一个突发事件。
异步事件是不可预见的,只能通过某些特定的方式来预防,或者说,
当该异步事件到来时,根据原来的设定完成相应的操作。
信号中断处理相关的术语
(1)产生信号:产生信号有多种说法。一个进程创建一个信号用于发送给另一个进程叫发送一个信号;
内核创建一个信号叫生成一个信号;一个进程向自己发送一个信号叫唤起一个信号。
(2)为使某个信号到来时进程能够执行相应的中断服务程序,即设置某信号到来时执行的代码,
称为安装中断。
(3)如果一个信号被正确发送到一个进程称为该信号被递送。
(4)如果一个信号的递送导致一段处理程序被执行,称为该信号被捕捉。
(5)如果一个信号被发送并且还没有引起任何动作(一般是对应进程阻塞了此信号),
称为这个信号处于等待状态。
信号处理办法
(1)忽略此信号。(2)捕捉信号。(3)执行系统默认操作。
signal安装信号
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
#define SIG_ERR /* return error*/
#define SIG_DFL /* default action*/
#define SIG_IGN /* ignore signal*/
sigaction安装信号
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
程序示例
接受信号,打印信息
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void myhandler(int sig);
int main()
{
struct sigaction act,oact;
act.sa_handler = myhandler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGUSR1,&act,&oact);
while(1)
{
printf("hello world\n");
pause();
}
}
void myhandler(int sig)
{
printf("i got signal : %d\n",sig);
}
信号集与屏蔽信号
信号忽略:系统仍然传递该信号,只是相应进程对该信号不作任何处理而已。
信号阻塞:系统不传递该信号,显示该进程无法接收到该信号,直到进程的信号集发生改变。
清空信号集
int sigemptyset(sigset_t *set);
完全填空信号集(阻塞所有信号)
int sigfillset(sigset_t *set);
添加信号到信号集中
int sigaddset(sigset_t *set, int signum);
从信号集中删除某个信号
int sigdelset(sigset_t *set, int signum);
检测信号是否在信号集中
int sigismember(const sigset_t *set, int signum);
设置和获取进程阻塞
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
程序示例
程序安装SIGUSR1,阻塞SIGUSR2
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
static void sig(int);
int main(int argc,char* argv[])
{
sigset_t newmask,oldmask,pendmask;
if(signal(SIGUSR1,sig) == SIG_ERR)
{
perror("signal");
exit(-1);
}
sigemptyset(&newmask);
sigaddset(&newmask,SIGUSR2);
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)
{
perror("signalmask ");
exit(-1);
}
while(1);
return 0;
}
static void sig(int signo)
{
printf("caught signo is %d,the process will quit\n",signo);
}
等待信号
pause函数用来等待除任意信号
用法示例:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handle()
{
printf("deal with...\n");
}
int main()
{
printf("begin...\n");
signal(SIGINT,handle);
pause();
printf("end...\n");
return 0;
}
而sigsuspend函数可以用来等待除指定信号(由其参数指定)外的任意信号
用法程序,其功能等效于pause
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handle()
{
printf("deal with...\n");
}
int main()
{
printf("begin...\n");
sigset_t sigmask;
sigemptyset(&sigmask);
signal(SIGINT,handle);
sigsuspend(&sigmask);
printf("end...\n");
return 0;
}
程序示例,功能屏蔽设置的信号。
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handle()
{
printf("deal with...\n");
}
int main()
{
printf("begin...\n");
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask,SIGINT);
signal(SIGINT,handle);
sigsuspend(&sigmask);
printf("end...\n");
return 0;
}
程序示例:
功能 sigprocmask函数阻塞信号,sigsuspend函数清空阻塞
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handle()
{
printf("deal with...\n");
}
int main()
{
printf("begin...\n");
sigset_t sigmask;
sigset_t sigmask2;
sigemptyset(&sigmask);
sigemptyset(&sigmask2);
sigaddset(&sigmask2,SIGINT);
signal(SIGINT,handle);
sigprocmask(SIG_BLOCK,&sigmask2,0);
int i;
for( i =0;i<5;i++)
{
printf("run...\n");
sleep(4);
printf("run end...\n");
sigsuspend(&sigmask);
printf("run again...\n");
sleep(4);
printf("end again ...\n");
}
printf("end...\n");
return 0;
}
程序示例
父进程执行文件拷贝,若收到子进程信号,则打印拷贝进度
子进程每隔固定时间,发送信号给父进程
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
int count;
int file_size;
void sig_alarm(int arg);
void sig_usr(int arg);
int main(int argc,char* argv[])
{
pid_t pid;
int i;
int fd_src,fd_des;
char buf[128];
if(argc != 3)
{
printf("check the format:comm src_file des_file\n");
return -1;
}
if((fd_src = open(argv[1],O_RDONLY)) == -1)
{
perror("open file src");
exit(-1);
}
file_size = lseek(fd_src,0,SEEK_END);
lseek(fd_src,0,SEEK_SET);
if((fd_des = open(argv[2],O_RDWR|O_CREAT,0644)) == -1)
{
perror("open fd_des");
exit(-1);
}
if((pid=fork()) == -1)
{
perror("fork");
exit(-1);
}
else if(pid > 0)
{
signal(SIGUSR1,sig_usr);
do
{
memset(buf,'\0',128);
if((i=read(fd_src,buf,1)) == -1)
{
perror("read");
exit(-1);
}
else if(i == 0)
{
kill(pid,SIGINT);
break;
}
else
{
if(write(fd_des,buf,i) == -1)
{
perror("write");
exit(-1);
}
count += i;
}
}
while(i != 0);
wait(pid,NULL,0);
exit(0);
}
else if(pid == 0)
{
usleep(2);
signal(SIGALRM,sig_alarm);
ualarm(1,1);
while(1){;}
exit(0);
}
}
void sig_alarm(int arg)
{
kill(getppid(),SIGUSR1);
}
void sig_usr(int arg)
{
float i;
i = (float)count / (float) file_size;
printf("cureent over:%0.0f%%\n",i*100);
}