收藏 分销(赏)

linux信号与系统调用的关系.doc

上传人:xrp****65 文档编号:8750317 上传时间:2025-02-28 格式:DOC 页数:7 大小:47.50KB 下载积分:10 金币
下载 相关 举报
linux信号与系统调用的关系.doc_第1页
第1页 / 共7页
linux信号与系统调用的关系.doc_第2页
第2页 / 共7页


点击查看更多>>
资源描述
信号与系统调用的关系: 当一个进程正在执行一个系统调用时,如果向该进程发送一个信号,那么对于大多数 系统调用来说,这个信号在系统调用完成之前将不起作用,因为这些系统调用不能被信号 打断。但是有少数几个系统调用能被信号打断,例如: wait(),pause()以及对慢速设备 (终端、 打印机等)的 read()、 write()、 open()等。如果一个系统调用被打断,它就返回-1,并将 errno 设为 EINTR。可以用下列代码来处理这种情况: if (wirte(tfd,buf,SIZE)<0) { if (errno==EINTR) { warn(“ Write interrupted.” ); … … } } 信号的复位: 在 Linux 中,当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信 号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用 相应的处理函数。下面的程序演示了这一点: #include <stdio.h> #include <signal.h> int catch(int sig); //信号绑定函数,必须在main函数前声明。 int main(void) { printf("the program is starting.\n"); signal(SIGINT, catch);//接受到SIGINT信号,执行绑定的catch函数 //signal(SIGINT, SIG_DFL);//SIG_DFL 恢复成系统的缺省动作 //signal(SIGINT, SIG_IGN);//告诉进程将 SIGINT 信号忽略,CTRL+C sleep(10); printf("the end.\n"); return 0; } int catch(int sig) { printf("Interrupt called.\n"); sleep(4); printf(“Interrupt Func end.\n”); } 执行它,结果如下: the program is starting. <ctrl+c> Interrupt called <ctrl+c> Interrupt Func end. Interrupt called Interrupt Func end. the end 只能保存一个CTRL+C。 如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中 断:the program is starting. <ctrl+c> Interrupt called <ctrl+\> Quit called Quit ended. Interrupt Func end。 the ended. 在进程间发送信号: 个进程通过对 signal()的调用来处理其它进程发送来的信号。一个进程也可以向其它的进程发送信号。这一操作是由系统调用 kill()来完成的。 kill()在 linux 系统库 signal.h中的函数声明:int kill(pid_t pid, int sig); 参数 pid 指定了信号发送的对象进程:它可以是某个进程的进程标识符(pid),也可以是以下的值: 如果 pid 为零,则信号被发送到当前进程所在的进程组的所有进程; 如果 pid 为-1 ,则信号按进程标识符从高到低的顺序发送给全部的进程(这个过程受 到当前进程本身权限的限制); 如果 pid 小于-1,则信号被发送给标识符为 pid 绝对值的进程组里的所有进程。 需要说明的是,一个进程并不是向任何进程均能发送信号的,这里有一个限制,就是 普通用户的进程只能向具有与其相同的用户标识符的进程发送信号。也就是说,一个用户 的进程不能向另一个用户的进程发送信号。只有 root 用户的进程能够给任何线程发送信号。 参数 sig 指定发送的信号类型。它可以是任何有效的信号。 由于调用 kill()的进程需要直到信号发往的进程的标识符,所以这种信号的发送通常只 在关系密切的进程之间进行,比如父子进程之间。 下面是一个使用 kill()调用发送信号的例子。这个程序建立两个进程,并通过向对方发 送信号 SIGUSR1 来实现它们之间的同步。这两个进程都处于一个死循环中,在接收对方发 送的信号之前,都处于暂停等待中。这是通过系统调用 pause()来实现的,它能够使一个程 序暂停,直至一个信号到达,然后进程输出信息,并用 kill 发送一个信号给对方。当用户 按了中断键,这两个进程都将终止。 #include <signal.h> int ntimes=0; main() { int pid,ppid; int p_action(), c_action(); /* 设定父进程的 SIGUSR1 */ signal(SIGUSR1,p_action); switch(pid=fork()) { case -1: /*fork 失败*/ perror("synchro"); exit(1); case 0: /*子进程模块*/ /* 设定子进程的 SIGUSR1 */ signal(SIGUSR1,c_action); /* 获得父进程的标识符*/ ppid=getppid(); for(;;) { sleep(1); kill(ppid,SIGUSR1); pause(); } - 58- Linux 网络编程 /*死循环*/ break; default: /*父进程模块*/ for (;;) { pause(); sleep(1); kill(pid,SIGUSR1); } /*死循环*/ } } p_action() { printf("Patent caught signal #%d\n",++ntimes); } c_action() { printf("Child caught signal #%d\n",++ntimes); } 程序运行结果如下: Patent caught signal #1 Child caught signal #1 Patent caught signal #2 Child caught signal #2 Patent caught signal #3 Child caught signal #3 Patent caught signal #4 Child caught signal #4 <ctrl+c> kill 命令用于向一个运行进程发送信号,它发送的信号默认为 SIGTERM,但是也可以指定为其它信号。我们可以直接用信号的号码来指定 kill 命令所发送信号之类型,也可以用符号名指定。比如可以用下面的命令来完成向进程标识符为 1234 的进程发送 SIGINT 信号: kill – s SIGINT 1234 系统调用 alarm() 和 pause(): alarm()它可以建立一个进程的报警时钟,在时钟定时器到时的时候,用信号向程序报告。alarm()系统调用在 Linux 系统函数库 unistd.h 中的函数声明如下: unsigned int alarm(unsigned int seconds); 函数唯一的参数是 seconds ,其以秒为单位给出了定时器的时间。当时间到达的时候, 就向系统发送一个 SIGARLM 信号。例如: alarm(60); 这一调用实现在 60 秒后发一个 SIGALRM 信号。alarm 不会象 sleep 那样暂停调用进 程的执行,它能立即返回,并使进程继续执行,直至指定的延迟时间到达发出 SIGALRM 信号。事实上,一个由 alarm()调用设置好的报警时钟,在通过 exec() 调用后,仍将继续有 效。但是,它在 fork() 调用后中,在子进程中失效。 如果要使设置的报警时钟失效,只需要调用参数为零的 alarm(): alarm(0) alarm()调用也不能积累。如果调用 alarm 两次,则第二次调用就取代第一次调用。但 是,后一个alarm会把前一个alarm的剩余时间作为返回值,然后自己重新从0开始计数,前一个alarm就此成为历史。 当需要对某项工作设置时间限制时,可以使用 alarm()调用来实现。其基本方法为:先 调用 alarm()按时间限制值设置报警时钟,然后进程作某一工作。如果进程在规定时间以内 完成这一工作,就再调用 alarm(0)使报警时钟失效。如果在规定时间内未能完成这一工作, 进程就会被报警时钟的 SIGALRM 信号中断,然后对它进行校正。 下面这个程序使用上述方法来强制用户作出回答。在其中包括一个 quickreply()函数, 它有一个参数 prompt,它是一个指向提示字符串的指针。quickreply 的返回值也是一个指 针。它指向含有输入行信息的字符串。这个例行程序在试作五次之后,如果仍未得到输入 信息,就返回一个 null 指针。每当 quickreply 要提醒用户时,它就向终端发送 ASCII 码 007,这会使终端响铃。quickreply 调用了标准 I/O 库中的例行程序 gets()。gets()把标准输入上的下一行信息存入一个字符型数组,它返回一个指向该数组的指针。当到达文件末或出错时,gets 则返回一个 null 指针。函数 catch 是信号 SIGALRM 的关联函数,它完成对此信号的处理。catch设置了一个 timed_out 标志,在 quickreply 中对这个标志进行检查,看它是否超过了规定的时限。 #include <stdio.h> #include <signal.h> #define TIMEOUT 5 #define MAXTRIES 5 #define LINESIZE 100 #define BELL '\007' #define TRUE 1 #define FALSE 0 /* 判断超时是否已经发生的标志*/ static int time_out; static char inputline[LINESIZE]; char* quickreply (char* prompt); - 60- Linux 网络编程 main() { printf("%s\n",quickreply("Input")); } char* quickreply (char* prompt) { int (*was)(),catch(),ntries; char* answer; /* 设定捕捉 SIGALRM 的的关联并保存原有关联*/ was=signal(SIGALRM,catch); for (ntries=0;ntries<MAXTRIES;ntries++) { time_out=FALSE; printf("\n%s>",prompt); /* 设定定时器*/ alarm(TIMEOUT); /* 获取输入*/ answer=gets(inputline); /* 关闭定时器*/ alarm(0); if (!time_out) break; } /* 恢复原有的 SIGALRM 关联*/ signal(SIGALRM,was); return (time_out?((char*) 0):answer); } /* SIGALRM 信号处理函数*/ catch() { /* 设定超时标志*/ time_out=TRUE; /* 响铃警告*/ putchar(BELL); } 2.系统调用 pause() 系统调用 pause()能使调用进程暂停执行,直至接收到某种信号为止。pause()在 Linux 系统函数库 unistd.h 中的函数声明如下: int pause(void); 该调用没有任何的参数。它的返回始终是 -1 ,此时 errno 被设置为ERESTARTNOHAND 。 下面这个程序为了在规定时间显示一个消息,使用了 alarm 和 pause。对它的调用方法 如下: $tml minutes message-text & 第一个参数为时间数,第二个参数为显示的消息。 #include <stdio.h> #include <signal.h> #define TRUE 1 #define FALSE 0 #define BELLS "\007\007\007" int alarm_flag=FALSE; /* SIGALRM 处理函数*/ setflag() { alarm_flag=TRUE; } main(int argc,char* argv[]) { int nsecs; int i; if (argc<2) { fprintf(stderr,"Usage:tml #minutes message\n"); exit(1); } if ((nsecs=atoi(argv[1])*60)<=0) { fprintf(stderr,"Invalid time\n"); exit(2); } /* 设定 SIGALRM 的关联动作*/ signal(SIGALRM,setflag); - 62- Linux 网络编程 /* 设定定时器*/ alarm(nsecs); /*使用 pause()调用等待信号*/ pause(); if (alarm_flag) { printf(BELLS); for (i=2;i<argc;i++) { printf("%s\n",argv[i]); } } exit(0); }
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服