linux多进程——进程组与会话、守护进程、信号通信 .

来源:互联网 发布:舒耐止汗喷雾危害 知乎 编辑:程序博客网 时间:2024/05/17 02:56
[+]
  1. killraise 发信号一些相关知识可以参考 Linux 信号通信
  2. pause 将进程挂起直到捕捉到信号为止
  3. 举例1
 一、进程组与会话

    进程组:是一个或多个进程的集合。可以调用 getpgid(0) 或 getpgrp() 来得到。进程组ID为组长的进程ID。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。调用 setpgid() 加入一个现有的进程组或创建一个新的进程组。

 

    会话:一个或多个进程组的集合

 

 

       可以用 setsid() 建立新会话,则该进程会变成新会话的首进程,同时成为一个新进程组的组长进程,该进程没有控制终端

 

二、守护进程

    守护进程的特点:没有终端的限制,不受用户、终端或其它的变化而受到影响。

   

 创建守护进程的步骤:

 

    出错处理:因为守护进程不依赖于终端,所以出错信息是不能用 printf 滴,这..... 怎么办?莫怕,用 syslog() 就能搞定~

 

     用系统日志就要调用三个函数:openlog()、syslog()、closelog()  系统日志存于 /var/log/messages

 

举例:

[cpp] view plaincopyprint?
  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<syslog.h>   
  5.   
  6. int main(){  
  7.     pid_t pid,s;  
  8.     int i;  
  9.     char *buff="Daemon Test!\n";  
  10.     if((pid = fork())<0){  
  11.         printf("fork error!\n");  
  12.         exit(1);  
  13.     }else if(pid> 0){  
  14.         exit(0);  
  15.     }  
  16.       
  17.     //第一个参数为在消息之前加入的字符串,第二个参数在每个消息中包含进程的ID,第三个参数指定程序发送的消息类型  
  18.     openlog("daemon_testlog",LOG_PID,LOG_DAEMON);     
  19.     if((s=setsid())<0){  
  20.         //第一个参数为参数类型,第二个参数为信息字符串   
  21.         syslog(LOG_ERR,"%s\n","setsid error!");     
  22.     }  
  23.     chdir("/");  
  24.     umask(0);  
  25.     for(i=0;i<getdtablesize();i++){   //关闭文件描述  
  26.         close(i);  
  27.     }  
  28.     while(1){  
  29.         syslog(LOG_INFO,"%s\n",buff);  
  30.         sleep(10);  
  31.     }  
  32.     closelog();  
  33.     return 0;  
  34. }  

 

 

三、信号

 

    Linux对每种信号都制定了默认的操作。捕捉到信号可以采用默认的操作、可以忽略(SIGKILL 与 SIGSTOP除外)、也可以执行相应的自定义处理函数。

 

kill()、raise() 发信号。一些相关知识可以参考Linux 信号通信  

pause() 将进程挂起直到捕捉到信号为止。

 

举例1:

[cpp] view plaincopyprint?
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <signal.h>   
  4.   
  5. void my_func(int);  
  6.   
  7. int main() {  
  8.     printf("Wainting for signal: SIGINT/SIGQUIT...\n");  
  9.     signal(SIGINT,my_func);  
  10.     signal(SIGQUIT,my_func);  
  11.     pause();  
  12.     pause();  
  13.     exit(0);  
  14. }  
  15.   
  16. void my_func(int sign_no){  
  17.     if (sign_no==SIGINT) {  
  18.         printf("I got CTRL+C!\n");  
  19.     } else if (sign_no==SIGQUIT) {  
  20.         printf("I got CTRL+\\!\n");  
  21.     }   
  22. }  

举例2: 

[cpp] view plaincopyprint?
  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<signal.h>   
  5.   
  6. int main(){  
  7.     pid_t pid;  
  8.     if((pid = fork())<0){  
  9.         printf("fork error!\n");  
  10.         exit(1);  
  11.     }else if(pid == 0){  
  12.         printf("Child process wait for singal....a\n");  
  13.         raise(SIGSTOP);     //子进程向自己发送一个消息,线程停止  
  14.         printf("Child is dead\n");    //此句不会打出来,因为进程直接被kill了  
  15.     }else{  
  16.         sleep(10);  
  17.         kill(pid,SIGKILL);  
  18.         wait(NULL);  
  19.     }  
  20.     return 0;  
  21. }  

 

   alarm()  在进程中设置一个定时器,当时间到时,发出SIGALARM信号。一个进程只能有一个闹钟时间,新的将代替旧的。返回值为新旧时间差值。

 

举例:

[cpp] view plaincopyprint?
  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<signal.h>   
  5.   
  6. int main(){  
  7.     int ret=alarm(5);  
  8.     printf("alarm...%d\n",ret);  
  9.     sleep(3);  
  10.     ret=alarm(5);  
  11.   
  12.     printf("alarm...%d\n",ret);  
  13.     pause();  
  14.     printf("never show\n");  
  15.   
  16. }  


程序运行结果为:alarm...0    alarm....2  。 2为相差时间,程序收到SIGALARM默认执行的操作为终止线程。

 

sigaction()函数:signal()的高级版~

 

例子:

[cpp] view plaincopyprint?
  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<signal.h>   
  5.   
  6. void my_func(int);  
  7.   
  8.   
  9. int main(){  
  10.     struct sigaction sa,oldsa;  
  11.   
  12.     printf("waiting for SIGINT/SIGQUIT......\n");  
  13.     sa.sa_handler=my_func;         //设定处理函数  
  14.     sigemptyset(&sa.sa_mask);      //清空信号集合  
  15.     sa.sa_flags=0;                //对信号处理的选项一般设为0  
  16.   
  17.     sigaction(SIGINT,&sa,&oldsa);     //oldsa为保存旧的信号结构体  
  18.     sigaction(SIGQUIT,&sa,&oldsa);  
  19.   
  20.     pause();  
  21.     pause();  
  22.     pause();  
  23.     pause();  
  24.     pause();  
  25.     pause();  
  26.     pause();  
  27.   
  28. }  
  29.   
  30. void my_func(int sig){  
  31.     if(sig == SIGINT){  
  32.         printf("Receive CTRL+C!\n");  
  33.     }  
  34.     else if(sig == SIGQUIT){  
  35.         printf("Receive CTRL+\\!\n");  
  36.     }else  
  37.     printf("Receive Signal!\n");  
  38. }  


信号集

 

 

  通常就是这个步骤。清空信号集->添加信号->设置信号屏蔽->定义信号处理

 

举例:

[cpp] view plaincopyprint?
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <signal.h>   
  4. #include <sys/types.h>   
  5. #include <unistd.h>   
  6.   
  7. void my_func(int);  
  8.   
  9. int main() {  
  10.     struct sigaction sa1,sa2;  
  11.     sigset_t set;  
  12.     //清空   
  13.     if (sigemptyset(&set)<0) {  
  14.     perror("sigemptyset");  
  15.     exit(1);  
  16.     }  
  17.     //添加信号        
  18.     if (sigaddset(&set,SIGINT)<0) {  
  19.     perror("sigaddset SIGINT");  
  20.     exit(1);  
  21.     }  
  22.     if (sigaddset(&set,SIGQUIT)<0) {  
  23.     perror("sigaddset SIGQUIT");  
  24.     exit(1);  
  25.     }  
  26.     //设置信号     
  27.     if (sigismember(&set,SIGINT)) {  
  28.     sa1.sa_handler=my_func;  
  29.     sigemptyset(&sa1.sa_mask);  
  30.     sa1.sa_flags=0;  
  31.     sigaction(SIGINT,&sa1,NULL);  
  32.     }  
  33.   
  34.     if (sigismember(&set,SIGQUIT)) {  
  35.     sa2.sa_handler=SIG_DFL;  
  36.     sigemptyset(&sa2.sa_mask);  
  37.     sa2.sa_flags=0;  
  38.     sigaction(SIGQUIT,&sa2,NULL);  
  39.     }  
  40.     //设置屏蔽字   
  41.     if (sigprocmask(SIG_BLOCK,&set,NULL)<0) {  
  42.     perror("sigprocmask");  
  43.     exit(1);  
  44.     } else {  
  45.     printf("Signal set is blocked!\n");  
  46.     }  
  47.     while(1){  
  48.         int c=getchar();  
  49.     if ((c=='u')||(c=='U'))  
  50.         break;  
  51.     }  
  52.     //解除屏蔽字   
  53.     if (sigprocmask(SIG_UNBLOCK,&set,NULL)<0) {  
  54.     perror("sigprocmask");  
  55.     exit(1);  
  56.     } else {  
  57.     printf("Signal set is unblocked!\n");  
  58.     }  
  59. }  
  60.   
  61. void my_func(int sig){  
  62.     if(sig == SIGINT){  
  63.     printf("Receive CTRL+C!\n");  
  64.     }  
  65.     else if(sig == SIGQUIT){  
  66.         printf("Receive CTRL+\\!\n");  
  67.     }else  
  68.     printf("Receive signal!\n");  
  69. }  

 

 [注] 1、解锁的瞬间即调用处理函数。2、内核只会保存一个同类的信号,其他的都被丢掉了。

 

 

 

原创粉丝点击