1、signal函数

  Unix系统的信号机制最简单的接口是signal函数,函数原型如下:

  #include <signal.h>
  typedef void (*sighandler_t)(int);
  sighandler_t signal(int signum, sighandler_t handler);

signum表示信号名称,handler取值常量SIG_IGN(忽略此信号)、常量SIG_DFL(执行默认动作)或者接到此信号后要调用的函数的地址(调用信号处理程序)。

写个程序练习一下signal函数的使用,程序的功能是捕获子进程退出。程序如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/wait.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <errno.h>  7 #include <signal.h>  8 //信号处理程序  9 void sig_child(int signo) 10 { 11 int status; 12 if(waitpid(-1,&status,0) != -1) 13 printf("child process exit.status= %d\n",status); 14 else 15  { 16 perror("waitpid() error"); 17 exit(-1); 18  } 19 } 20 21 int main() 22 { 23  pid_t pid; 24 //创建子进程退出信号 25  signal(SIGCHLD,sig_child); 26 if((pid=fork()) == -1) 27 perror("fork() error"); 28 else if(pid == 0) 29  { 30 printf("I am child process.\n"); 31 exit(0); 32  } 33 else 34  { 35 sleep(3); //让子进程先执行 36 printf("I am parent process.\n"); 37  } 38 exit(0); 39 }

程序执行结果如下:

2、中断的系统调用

  如果进程在执行一个低速系统调用而阻塞期间捕获到一个信号,则该系统调用就被中断不再继续执行。系统调用返回出错,将errno的值设置为EINTR。当一个信号发生时,进程捕捉到,意味着已经发生了某种事情,可以唤醒阻塞系统调用进行相关操作。低速系统调用是可能使进程永远阻塞的一类系统调用。与被中断的系统调用相关的问题是必须显示的处理出错返回。例如在进行多操作时候,多的过程被中断了,中断结束后希望重新启动读操作。代码如下:

1 again:
2     if((n=read(fd,buf,BUFSIZE))<0) 3  { 4 if(errno == EINTR) 5 goto again; 6 /*handle other errnors*/ 7 }

自动重新启动的系统调用包括:ioctl、read、readv、write、writew、wait和waitpid。
3、可重入函数

  进程捕捉到信号并对其进行处理,进程正在执行的指令序列就被信号处理程序临时中断,首先执行该信号处理程序中的指令,如果从信号处理程序返回,则继续在捕捉到信号时进程正在执行的正常指令中返回。在信号处理程序中,不能判断捕捉到信号时进程在何处执行,这样不能保证在中断处理结束后能够正确返回到进程的执行指令中。为了保证进程在处理完中断后能够正确返回,需要保证调用的是可重入的函数。不可重入函数包括:(1)使用静态数据结构,(2)调用malloc或free,(3)标准I/O函数。信号处理程序中调用一个不可重入的函数,则结果是不可预测的。例如getpwnam函数是个不可重入的,因为其结果存放在静态存储单元中,信号处理程序调用后,返回给正常调用者的信息可能是被返回给信号处理程序的信息覆盖。程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h> #include <signal.h> #include <pwd.h> #include <string.h> static void my_alarm(int signo) { struct passwd *rootptr; printf("in signal handler.\n"); if ((rootptr = getpwnam("root")) == NULL) { perror("getpwnam() error"); exit(-1); } printf("return value:,pw_name = %s\n",rootptr->pw_name); alarm(1); } int main() { struct passwd *ptr; signal(SIGALRM,my_alarm); alarm(1); while(1) { if((ptr = getpwnam("anker")) == NULL) { perror("getpwnam() error"); exit(-1); } if(strcmp(ptr->pw_name,"anker") != 0) printf("return value corrupted!,pw_name = %s\n",ptr->pw_name); else printf("return value not corrupted!,pw_name = %s\n",ptr->pw_name); } }

编译执行程序,没有发现出现什么异常,此处有些不明白,日后过来想想。
4、kill和raise函数

  kill函数将信号发送给进程或者进程组,raise函数则允许进程向自身发送信号。进程将信号发送给其他进程需要权限,超级用户可以将信号发送给任一进程。调用kill产生的信号时不被阻塞的。函数原型如下:

  #include <sys/types.h>
  #include <signal.h>
  int kill(pid_t pid, int sig);
  int raise(int sig);    //等价于kill(getpid(),signo)

5、alarm和pause函数

  使用alarm函数设置计时器,在将来某个指定时间该计时器会超时,产生SIGALRM信号,默认动作时终止调用alarm函数的进程,每个进程只能有一个闹钟时钟,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。当在调用alarm()前已经设置了一个闹钟,那么我们可以调用alarm(0)来取消此闹钟,并返回剩余时间。puase函数使调用进程挂起直到捕捉到一个信号。只有执行了一个信号处理程序并从其返回时,pause才返回-1,并将errno设置为EINTR。函数原型如下:

  #include <unistd.h>
  unsigned int alarm(unsigned int seconds);  //返回0或者以前设置的闹钟时间的余留秒数
  int pause(void);

写个程序练习以上函数,程序如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/wait.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <errno.h>  7 #include <signal.h>  8 static void sig_kill(int signo)  9 { 10 printf("Received from kill().\n"); 11 } 12 static void sig_alarm(int signo) 13 { 14 printf("Receiver form aralm().\n"); 15 } 16 int main() 17 { 18 19  signal(SIGHUP,sig_kill); 20  signal(SIGALRM,sig_alarm); 21 22 printf("kill() is called.\n"); 23  kill(getpid(),SIGHUP); 24 printf("alarm() is called.\n"); 25 alarm(3); 26 printf("pause() is called.\n"); 27  pause(); 28 printf("raise() is called.\n"); 29  raise(SIGHUP); 30 exit(0); 31 }

程序执行结果如下:

alarm只设定一个闹钟,时间到达并执行其注册函数之后,闹钟便失效。如果想循环设置闹钟,需在其注册函数中在调用alarm函数。写个程序可以设置一个循环闹钟,使得程序每个多少秒执行以下,执行完成之后开始计时,时间都接着执行,循环指定主程序结束。程序如下:

 1 #include <unistd.h>
 2 #include <signal.h>
 3 #include <stdio.h>
 4 void sig_alarm(int signo)  5 {  6 printf("Alarming.\n");  7 signal(SIGALRM, sig_alarm); //让内核做好准备,一旦接受到SIGALARM信号,就执行sig_alarm  8 alarm(5);  9 } 10 void main() 11 { 12 int i; 13 signal(SIGALRM, sig_alarm);//让内核做好准备,一旦接受到SIGALARM信号,就执行sig_alarm 14 alarm(5); 15 for(i=1;i<21;i++) 16  { 17 printf("sleep %d ...\n",i); 18 sleep(1); 19  } 20 }

程序执行结果如下:

6、信号集

  通过信号集(signal set)表示多个信号,这样方便操作多个信号。信号集的数据类型为sigset_t,信号集操作函数如下: 

  #include <signal.h>
  int sigemptyset(sigset_t *set);  //初始化由set指向的信号集,清除其中所有信号
  int sigfillset(sigset_t *set);    //初始化由set指向的信号集,使其包括所有信号
  int sigaddset(sigset_t *set, int signum);   //添加一个指定的信号
  int sigdelset(sigset_t *set, int signum);   //删除一个指定信号
  int sigismember(const sigset_t *set, int signum);   //判断signum是否在set所指向的信号集中

  一个进程的信号屏蔽字规定了当前阻塞而不能递送给该进程的信号集,调用sigprocmask函数可以检测或更改其信号屏蔽字。函数原型如下:

  int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

  how的取值为:SIG_BLOCK、SIG_UNBLOCK、SIG_SETMASK

  sigpending函数返回信号集,其中的各个信号对于调用进程是阻塞的而不能传递。函数原型为:int sigpending(sigset_t *set)。

写个程序进行信号屏蔽测试,程序如下:

 1 #include <sys/wait.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <errno.h>
 5 #include <signal.h>
 6 #include <stdio.h>  7 #include <stdlib.h>  8  9 static void sig_quit(int signo); 10 11 int main() 12 { 13  sigset_t newmask,oldmask,pendmask; 14 if(signal(SIGQUIT,sig_quit) == SIG_ERR) 15  { 16 perror("signal() error"); 17 exit(-1); 18  } 19 sigemptyset(&newmask); 20 //添加一个退出信号 21 sigaddset(&newmask,SIGQUIT); 22 //将newmask信号机设置为阻塞,原信号集保存在oldmask中 23 if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) == -1) 24  { 25 perror("sigprocmask() error"); 26 exit(-1); 27  } 28 sleep(5); 29 //获取阻塞的信号集 30 if(sigpending(&pendmask) == -1) 31  { 32 perror("sigpending() error"); 33 exit(-1); 34  } 35 //判断SIGQUIT是否是阻塞的 36 if(sigismember(&pendmask,SIGQUIT)) 37 printf("\nSIGQUIT is pending.\n"); 38 //回复原理的信号集 39 if(sigprocmask(SIG_SETMASK,&oldmask,NULL) == -1) 40  { 41 perror("sigprocmask() error"); 42 exit(-1); 43  } 44 printf("SITQUIT unblocked\n"); 45 sleep(5); 46 exit(0); 47 } 48 49 static void sig_quit(int signo) 50 { 51 printf("caught SIGQUIT.\n"); 52 if(signal(SIGQUIT,SIG_DFL) == SIG_ERR) 53  { 54 perror("signal() error"); 55 exit(-1); 56  } 57 }

程序执行结果如下:在中断上键入Ctlr+\退出字符。

第二次运行时候,在进程休眠的时候产生多次SIGQUIT信号,但是解除了该信号的阻塞后,只会向进程发送一个SIGQUIT,系统没有对信号进行排队。

  接着昨天学习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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <signal.h>
 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_INTERRUPT 18 act.sa_flags |= SA_INTERRUPT; 19 #endif 20  } 21 else //其余信号设置为系统调用自动重启 22  { 23  #ifdef SA_RESTART 24 act.sa_flags |= SA_RESTART; 25 #endif 26  } 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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <errno.h>
 6 #include <signal.h>  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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <signal.h>
 6 #include <errno.h>  7 #include <setjmp.h>  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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <errno.h>
 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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <errno.h>
 6 #include <signal.h>  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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <errno.h>
 6 #include <signal.h>  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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <errno.h>
 6 #include <signal.h>  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 else 51  { 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 <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <errno.h>
 6 #include <signal.h>  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 }

程序执行结果如下:

转载于:https://www.cnblogs.com/alantu2018/p/8466075.html

Unix环境高级编程(十)信号续相关推荐

  1. Unix环境高级编程(十五)高级I/O

    1.非阻塞I/O 对低速设备的I/O操作可能会使进程永久阻塞,这类系统调用主要有如下情况: (1)如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道.终端设备和网络设备). (2)如果数据不 ...

  2. 《unix环境高级编程》--- 信号

    信号是软件中断. #include <signal.h>void (*signal(int signo, void (*func)(int)))(int); 该函数有2各参数,第一个为信 ...

  3. (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  4. 《Unix环境高级编程》学习笔记:从点到面

    以前在课堂上学习过<Unix初级教程(第四版)>,对于Unix有了一点了解.由于以后使用的需要,要对它进行比较深入的学习,为此需要阅读不少的书籍,这本<Unix环境高级编程>便 ...

  5. Unix环境高级编程 笔记

    Unix环境高级编程(第二版)学习笔记 这是一次较长时间的整理,然而跳跃了一些章节和很多知识点,仍然是很不完善很不全面的. 前言 操作系统某些问题 严格意义上,可将操作系统定义为一种软件,它控制计算机 ...

  6. 5w字总结 Unix系统编程学习笔记(面试向)(Unix环境高级编程/Unix环境程序设计)

    文章目录 一.计算 C语言的数据表示与处理 计算 C语言的基本运算操作 内存表和符号表 类型转换 函数类型的分析 指令 复合指令 句法 函数 函数激活(Activation Record) 函数激活定 ...

  7. unix环境高级编程 pdf_UNIX系统编程宝典,每一本都值得程序员珍藏

    这几本UNIX系统编程宝典,重印无数次,几代程序员都视如珍宝的几本书,小编在出版圈里快十年了,见证了这本书图灵版.异步社区版的出版.营销,对这套书倾注了一定的感情.今天继续分享给你们,好书总会有人还不 ...

  8. UNIX环境高级编程笔记

    1.setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, len);   SO_REUSEADDR套接口选项允许为以下四个不同的目的提供服务:   ...

  9. [阅读体会] UNIX环境高级编程

    文章目录 写在开始阅读前 (我会的知识点,在体会里是不提的,并不是书中没有,这里着重于记录我之前不会的,但读过书之后学会的.) 第一章 第二章 2.1 引言 2.2 UNIX标准化 2.2.1 ISO ...

最新文章

  1. mysql 查询不使用索引_简单的mySQL查询不使用索引
  2. IBM首席执行官提出人工智能部署三大基本原则
  3. 判断单链表是否存在环
  4. ORACLE B-TREE(B树)索引
  5. 是个狠角色。。 | 今日最佳
  6. 与计算机相关的社团活动,计算机社团活动记录.doc
  7. python两个时间内的工作日_如何在Python中找到两个日期之间的星期一或任何其他工作日的数目?...
  8. 安卓案例:帧式布局演示(切换颜色)
  9. 银行存款都有哪些误区,你都有踩坑吗?
  10. python网络数据采集(伴奏曲)
  11. python发邮件详解_用Python3发送邮件详解
  12. if else if与if if语句的区别
  13. php mysql统计去掉重复的,php - Mysql:根据最小数量删除重复记录 - 堆栈内存溢出...
  14. SPI 接口OLED 使用5V 信号驱动可能需要电平转换
  15. 流媒体后视镜前装搭载小幅下滑,远峰与镜泰排位争夺白热化
  16. 2016最新php授权验证系统v2.1,2016PHP受权验证系统V2.1完整版,域名+IP双重验证 一键升级受权系统 完美无错...
  17. 基于C的VAD实现一
  18. mysql 数据转移历史表_mysql 历史数据表迁移方案
  19. 算法分析一:基础知识
  20. python绘制多个散点图_绘制多个散点图熊猫

热门文章

  1. android 弹窗圆角,Android开发笔记: Android最简单的圆角提示框
  2. java代码写selector_javaNIO:选择器--实践 Selector
  3. 数据库设计的三大范式[学习笔记]
  4. 爬虫入门-京东评论爬取和简单分析[学习笔记]
  5. 如何快速上手一个项目
  6. 电脑插上U盘双击打不开应用程序右键可以打开问题
  7. matlab虚拟现实之V-Realm Builder2建模注意事项
  8. 数据结构和算法 D3
  9. mex2 Inputs and Outputs
  10. 3D数学之矩阵的各种求逆