博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《APUE》读书笔记—第十章信号(下)
阅读量:6566 次
发布时间:2019-06-24

本文共 11655 字,大约阅读时间需要 38 分钟。

  接着昨天学习Unix信号机制,信号内容挺多了,发了两天的时间才了解各大概,日后遇到问题需要多看几遍,掌握核心应用。

7、sigaction函数

sigaction函数的功能是检查或修改与指定信号相关联的处理动作或同时执行这两种操作,可以用sigaction函数实现signal函数。函数原型及结构参数如下:

  int sigaction(int signum, const struct sigaction *act,struct sigaction *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);
  };

现用sigaction函数实现signal函数,被信号中断的系统调用都能够重启。程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 typedef void Sigfunc(int); 8 9 Sigfunc* mysignal(int signo,Sigfunc *func)10 {11 struct sigaction act,oact;12 act.sa_handler = func; //设置中断处理程序13 sigemptyset(&act.sa_mask); //初始化信号集14 act.sa_flags = 0;15 if(signo == SIGALRM) //将SIGALRM信号设置为系统调用不会自动重启16 {17 #ifdef SA_INTERRUPT18 act.sa_flags |= SA_INTERRUPT;19 #endif20 }21 else //其余信号设置为系统调用自动重启22 {23 #ifdef SA_RESTART24 act.sa_flags |= SA_RESTART;25 #endif26 }27 if(sigaction(signo,&act,&oact)<0)28 return (SIG_ERR);29 return (oact.sa_handler);30 }31 32 static void sig_func(int signo)33 {34 printf("Recevied a SIGALRM signal.\n");35 }36 37 int main()38 {39 printf("Starting.\n");40 mysignal(SIGALRM,sig_func);41 alarm(2);42 pause(); //等待信号出现43 exit(0);44 }

程序执行结果如下:

8、sigsetjmp和siglongjmp函数

 这两个函数是对非局部转移的setjmp和longjmp函数的改进,在信号处理程序中进行非局部转移时应当使用这两个函数。函数原型如下:  

   int sigsetjmp(sigjmp_buf env, int savesigs);

   void siglongjmp(sigjmp_buf env, int val);

在sigsetjmp函数中,如果savesigs非0,则sigsetjmp在env中保存进程的当前信号屏蔽字,调用siglongjmp从其中恢复保存的信号屏蔽字。

写个程序练习一下,程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 static void printcharacter(const char* str); 9 static void sig_usr(int signo);10 void TELL_WAIT(void);11 void TELL_PARENT(pid_t pid);12 void TELL_CHILD(pid_t pid);13 void WAIT_PARENT(void);14 void WAIT_CHILD(void);15 static volatile sig_atomic_t sigflag;16 static sigset_t newmask,oldmask,zeromask;17 18 int main()19 {20 pid_t pid;21 TELL_WAIT();22 pid = fork();23 switch(pid)24 {25 case -1:26 perror("fork() error");27 exit(-1);28 case 0: //让子进程优先执行29 //WAIT_PARENT();30 printcharacter("output from child prcess.\n");31 TELL_PARENT(getppid());32 break;33 default:34 WAIT_CHILD();35 printcharacter("output from parent prcess.\n");36 //TELL_CHILD(pid);37 }38 exit(0);39 }40 41 static void printcharacter(const char* str)42 {43 const char *ptr;44 setbuf(stdout,NULL);45 for(ptr=str;*ptr!='\0';ptr++)46 putc(*ptr,stdout);47 }48 static void sig_usr(int signo) //信号处理程序49 {50 sigflag = 1;51 }52 void TELL_WAIT(void)53 {54 signal(SIGUSR1,sig_usr);55 signal(SIGUSR2,sig_usr);56 sigemptyset(&zeromask);57 sigemptyset(&newmask);58 //添加信号集59 sigaddset(&newmask,SIGUSR1);60 sigaddset(&newmask,SIGUSR2);61 sigprocmask(SIG_BLOCK,&newmask,&oldmask); //设置信号为阻塞62 }63 void TELL_PARENT(pid_t pid)64 { 65 kill(pid,SIGUSR2); //向子进程发送信号66 }67 void TELL_CHILD(pid_t pid)68 {69 kill(pid,SIGUSR1);//向父进程发送信号70 } 71 void WAIT_PARENT(void)72 {73 while(sigflag == 0)74 sigsuspend(&zeromask);75 sigflag = 0;76 sigprocmask(SIG_SETMASK,&oldmask,NULL);77 }78 void WAIT_CHILD(void)79 {80 while(sigflag == 0)81 sigsuspend(&zeromask); //阻塞进程82 sigflag = 0;83 sigprocmask(SIG_SETMASK,&oldmask,NULL);84 }

程序执行结果如下:

 当调用一个信号处理程序时,被捕捉到的信号添加到进程的当前信号屏蔽字中,当从信号处理程序返回时,恢复原来的屏蔽字,siglongjmp恢复了有sigsetjmp保存的信号屏蔽字。

9、sigsuspend函数

  该函数在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。函数原型如下:

  int sigsuspend(const sigset_t *mask); //返回-1,并将errno设置为EINTR

  将信号屏蔽字设置为mask指向的值,在捕捉到一个信号或发生一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号程序返回,则sigsuspend返回,并且该进程的信号屏蔽字设置为调用sigsuspend之前的值。该函数可以保护不希望由信号中断的代码临界区,写个程序,使用该函数保护临界区,使其不被特定信号中断,程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 void pr_mask(const char *str); 9 static void sig_int(int);10 11 int main()12 {13 sigset_t newmask,oldmask,waitmask;14 pr_mask("program start: ");15 signal(SIGINT,sig_int);16 sigemptyset(&waitmask);17 sigaddset(&waitmask,SIGUSR1);18 sigemptyset(&newmask);19 sigaddset(&newmask,SIGINT);20 sigprocmask(SIG_BLOCK,&newmask,&oldmask);21 pr_mask("in critical region");22 //修改进程屏蔽字,在捕捉信号之前,将进程挂起23 sigsuspend(&waitmask);24 pr_mask("after return form sigsuspend: ");25 sigprocmask(SIG_SETMASK,&oldmask,NULL);26 pr_mask("program exit: ");27 exit(0);28 }29 30 void pr_mask(const char *str)31 {32 sigset_t sigset;33 int errno_save;34 errno_save = errno;35 if(sigprocmask(0,NULL,&sigset)<0)36 {37 perror("sigprocmask() error");38 exit(-1);39 }40 printf("%s\n",str);41 if(sigismember(&sigset,SIGINT))42 printf("SIGINT \n");43 if(sigismember(&sigset,SIGQUIT))44 printf("SIGQUIT \n");45 if(sigismember(&sigset,SIGUSR1))46 printf("SIGUSR1 \n");47 if(sigismember(&sigset,SIGALRM))48 printf("SIGALRM \n");49 errno = errno_save;50 }51 52 static void sig_int(int signo)53 {54 pr_mask("\nin sig_int: ");55 }

 程序执行结果如下:

从结果可以看出在调用sigsuspend函数,将SIGUSR1信号添加到进程信号屏蔽字中,当从sissuspend返回时,信号屏蔽字恢复为调用它之前的值。

进程之间存在资源竞争,程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 static void printcharacter(const char* str) 8 { 9 const char *ptr;10 setbuf(stdout,NULL);11 for(ptr=str;*ptr!='\0';ptr++)12 putc(*ptr,stdout);13 }14 15 int main()16 {17 pid_t pid;18 pid = fork();19 switch(pid)20 {21 case -1:22 perror("fork() error");23 exit(-1);24 case 0:25 printcharacter("output from child prcess.\n");26 break;27 default:28 printcharacter("output from parent prcess.\n");29 }30 exit(0);31 }

 程序执行结果如下:

  从结果看出,父子进程之间存在资源竞争,导致输出结果是随机的。接下来采用信号机制实现父子进程之间的同步实现TELL_WAIT、TELL_PARENT、TELL_CHILD、  WAIT_PARENT和WAIT_CHILD。程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 static void printcharacter(const char* str); 9 static void sig_usr(int signo);10 void TELL_WAIT(void);11 void TELL_PARENT(pid_t pid);12 void TELL_CHILD(pid_t pid);13 void WAIT_PARENT(void);14 void WAIT_CHILD(void);15 static volatile sig_atomic_t sigflag;16 static sigset_t newmask,oldmask,zeromask;17 18 int main()19 {20 pid_t pid;21 TELL_WAIT();22 pid = fork();23 switch(pid)24 {25 case -1:26 perror("fork() error");27 exit(-1);28 case 0:29 //WAIT_PARENT();30 printcharacter("output from child prcess.\n");31 TELL_PARENT(getppid());32 break;33 default:34 WAIT_CHILD();35 printcharacter("output from parent prcess.\n");36 //TELL_CHILD(pid);37 }38 exit(0);39 }40 41 static void printcharacter(const char* str)42 {43 const char *ptr;44 setbuf(stdout,NULL);45 for(ptr=str;*ptr!='\0';ptr++)46 putc(*ptr,stdout);47 }48 static void sig_usr(int signo)49 {50 sigflag = 1;51 }52 void TELL_WAIT(void)53 {54 signal(SIGUSR1,sig_usr); //设置信号55 signal(SIGUSR2,sig_usr);56 sigemptyset(&zeromask);57 sigemptyset(&newmask);58 sigaddset(&zeromask,SIGUSR1);59 sigaddset(&newmask,SIGUSR2);60 sigprocmask(SIG_BLOCK,&newmask,&oldmask); //将信号设置为阻塞61 }62 void TELL_PARENT(pid_t pid)63 {64 kill(pid,SIGUSR2); //向子进程发生信号65 }66 void TELL_CHILD(pid_t pid)67 {68 kill(pid,SIGUSR1); //想父进程发送信号69 }70 void WAIT_PARENT(void)71 {72 while(sigflag == 0)73 sigsuspend(&zeromask);//将进程挂起。等待信号处理程序返回74 sigflag = 0;75 sigprocmask(SIG_SETMASK,&oldmask,NULL);76 }77 void WAIT_CHILD(void)78 {79 while(sigflag == 0)80 sigsuspend(&zeromask); //将进程挂起。等待信号处理程序返回81 sigflag = 0;82 sigprocmask(SIG_SETMASK,&oldmask,NULL);83 }

 程序执行结果如下:

10、abort函数

  abort函数的功能是使异常终止,此函数将SIGABRT信号发送给调用进程,让进程捕捉SIGABRT信号目的是在进程终止之前由其执行所需的清理操作。默认情况是终止调用进程。可以采用sigaction和kill函数来实现abort,程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 void myabort() 9 {10 sigset_t mask;11 struct sigaction action;12 sigaction(SIGABRT,NULL,&action);13 if(action.sa_handler == SIG_IGN)14 {15 action.sa_handler = SIG_DFL;16 sigaction(SIGABRT,&action,NULL);17 }18 if(action.sa_handler == SIG_DFL)19 fflush(NULL);20 sigfillset(&mask);21 sigdelset(&mask,SIGABRT);22 sigprocmask(SIG_SETMASK,&mask,NULL);23 kill(getpid(),SIGABRT);24 fflush(NULL);25 action.sa_handler = SIG_DFL;26 sigaction(SIGABRT,&action,NULL);27 sigprocmask(SIG_SETMASK,&mask,NULL);28 kill(getpid(),SIGABRT);29 exit(1);30 }31 static void sig_abort(int signo)32 {33 printf("abort signal.\n");34 }35 36 int main()37 {38 signal(SIGABRT,sig_abort);39 myabort();40 pause();41 exit(0);42 }

执行结果如下:

11、system函数

  POSIX.1要求system函数忽略SIGINT和SITQUIT信号,阻塞SIGCHLD。采用信号实现一个system函数,程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 int mysystem(const char*cmdstring) 9 {10 pid_t pid;11 int status;12 struct sigaction ignore,saveintr,savequit;13 sigset_t chldmask,savemask;14 15 if(cmdstring == NULL)16 return 1;17 ignore.sa_handler = SIG_IGN;18 sigemptyset(&ignore.sa_mask);19 ignore.sa_flags = 0;20 if(sigaction(SIGINT,&ignore,&savequit)<0)21 {22 perror("sigaction() error");23 exit(-1);24 }25 if(sigaction(SIGQUIT,&ignore,&savequit) <0)26 {27 perror("sigaction() error");28 exit(-1);29 }30 sigemptyset(&chldmask);31 sigaddset(&chldmask,SIGCHLD);32 if(sigprocmask(SIG_BLOCK,&chldmask,&savemask) < 0)33 {34 perror("sigprocmask() error");35 exit(-1);36 }37 if((pid = fork()) == -1)38 {39 perror("fork() error");40 exit(-1);41 }42 else if(pid == 0)43 {44 sigaction(SIGINT,&saveintr,NULL);45 sigaction(SIGQUIT,&savequit,NULL);46 sigprocmask(SIG_SETMASK,&savemask,NULL);47 execl("/bin/sh","sh","-c",cmdstring,(char *)0);48 _exit(-127);49 }50 else51 {52 while(waitpid(pid,&status,0) < 0)53 {54 if(errno != EINTR)55 {56 status = -1;57 break;58 }59 }60 }61 if (sigaction(SIGINT,&saveintr,NULL)<0)62 return -1;63 }64 65 int main()66 {67 printf("Pint date:\n");68 mysystem("date");69 printf("Print process:\n");70 mysystem("ps");71 exit(0);72 }

程序执行结果如下:

12、sleep函数

此函数使调用进程被挂起,直到满足下列条件之一:(1)已经经过seconds所指定的墙上时钟时间(2)调用进程捕捉到一个信号并从信号处理程序返回。sleep的可靠实现如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 static void sig_alrm(int signo) 9 {10 11 }12 13 unsigned int mysleep(unsigned int nsecs)14 {15 struct sigaction newact,oldact;16 sigset_t newmask,oldmask,suspmask;17 unsigned int unslept;18 19 newact.sa_handler = sig_alrm;20 sigemptyset(&newact.sa_mask);21 newact.sa_flags = 0;22 sigaction(SIGALRM,&newact,&oldact);23 sigemptyset(&newmask);24 sigaddset(&newmask,SIGALRM);25 sigprocmask(SIG_BLOCK,&newmask,&oldmask);26 alarm(nsecs);27 suspmask = oldmask;28 sigdelset(&suspmask,SIGALRM);29 sigsuspend(&suspmask);30 unslept = alarm(0);31 sigprocmask(SIG_SETMASK,&oldmask,NULL);32 return unslept;33 }34 35 int main()36 {37 int i;38 printf("Program starting.\n");39 printf("sleep 5 seconds.....\n");40 for(i=1;i<=5;++i)41 {42 printf("The %dth second.\n",i);43 mysleep(1);44 }45 printf("wake up.\n");46 exit(0);47 }

程序执行结果如下:

转载地址:http://xjjjo.baihongyu.com/

你可能感兴趣的文章
Office 365系列之十:批量部署O365客户端
查看>>
Spring Cloud源码分析(二)Ribbon(续)
查看>>
SystemCenter2012SP1实践(5)SCVMM管理HyperV
查看>>
了解DELL的raid卡电池相关信息
查看>>
教你一招超级简单的方法快速搞定grub.conf文件的丢失及损坏
查看>>
06-Windows Server 2012 R2 会话远程桌面-标准部署-RD网关(RemoteApp)
查看>>
CCNA(Stand-ALONE)Lab 10-ARP
查看>>
Tomcat 与 Resin PK大战
查看>>
Android--SoundPool
查看>>
MySQL 存储过程
查看>>
Azure操作手册集合
查看>>
安装Windows Vista
查看>>
Snap和Flatpak 通吃所有发行版的打包方式。
查看>>
pandas groupby
查看>>
SQL Server 2005 For XML[学习]
查看>>
Asp.Net中验证控件简单分析
查看>>
EF 4.1+MVC3+Jquery Ajax+Json.Net+JqueryUI+IUnitOfWork+Repository 学习DEMO(暂停更新)
查看>>
EBS R12.2 ADOP (R12.2 AD Online Patching) - 1
查看>>
分钱单算法
查看>>
Node.js制作图片下载爬虫的一般步骤
查看>>