现在的位置: 首页 > 综合 > 正文

linux进程知识 Linux 信号通信

2017年11月03日 ⁄ 综合 ⁄ 共 19249字 ⁄ 字号 评论关闭

一、程序存储

      经常被问到进程与线程的区别,今天有人问程序与进程的区别,一下子还真没反应过来 敲打  。程序只是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体。而进程则不同,它是程序在某个数据集上的执行。进程是一个动态的实体,它有自己的生命周期。反映了一个程序在一定的数据集上运行的全部动态过程。 

 

 

二、crontab

 

基本格式 :
*  *  *  *  *  command
分 时 日 月 周 命令

第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令

 

在终端输入:crontab -e

然后编辑内容为:* * 9 10 0 echo "now the time is .... `date` " >>/home/fsy/io/tempfile

查看:crontab -l

删除:crontab -r

 

 

三、关于fork 进程的补充

   1、用重定向方式输出时应该注意:调用fork的程序,会完全复制一个父进程。所以也会复制一个缓冲区,及如果父进程在缓冲区中有内容,则子进程也会一并获得。那为什么对文件的读写不是两个文件呢?因为子进程复制的是文件标示符,转成文件指针会指向同一个文件。

 

    2、fork用于父子进程同时指行不同的代码段,比如网络服务进程。或用于要执行一个不同的程序,通常是子进程从fork返回后立即调用exec。

 

    3、vfrok()不复制父进程的地址空间。子进程一定是先运行。在调用exec/exit之前,它在父进程的空间中运行

 

四、exec族

  函数还真多,就是功能都一样。一大家子人,长的还差不多,只能干一样事。这存在感,真服了敲打

 

 

 个人感觉记住一个就行:execlp("ls","ls","-l",NULL);

 

 错误判断:

errno=ENOENT    找不到文件或路径

errno=EFAULT     argv/envp忘记用NULL结束

errno=EACCES    没有运行权限

 

 

五、exit()与_exit()

 

    最好使用exit()退出程序。因为会清空缓存。exit()在<stdlib.h>中。_exit()在<unistd.h>中。中间的参数,可以用wait系统调用接收子进程返回值。

 

六、wait与waitpid()

 

  wait()使父进程阻塞直到子进程结束才返回。wait()是waitpid()的一个特例。所以waitpid()更牛一些~

   

 

    通常说来waitpid(),用于等待一个特定的子进程。调用方法为:waitpid(pid1, &stu, WNOHANG) 或者 waitpid(pid1, NULL, 0)微笑

 

 

七、孤儿与僵尸(进程)

   这个...不知道是作者有才,还是翻译有思想,弄出了这么俩词 尴尬 

 

     父进程先死了,子进程就是孤儿了。但是别担心,咱是和 *谐社会,怎么能有孤儿呢?所以马上有个大爹——init 收养这些没人要的进程。

 

    要是子进程先死了,父进程没回收子进程,那他就成了孤魂野鬼。也就变僵尸了惊恐 
所以父进程要收尸啊...... 这个也好解决。收尸其实也不费劲,调用wait()/waitpid()就行。这个到处都是僵尸,对社会的安定团结还是有很大影响的。系统所能使用的进程号是有限的,子进程不回收,虽然不占内存了,但是进程号还占着,僵尸多了,正常的子进程就没有进程号了......

 

 

 

一、进程组与会话

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

 

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

 

 

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

 

二、守护进程

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

   

 创建守护进程的步骤:

 

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

 

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

 

举例:

  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:

  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: 

  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信号。一个进程只能有一个闹钟时间,新的将代替旧的。返回值为新旧时间差值。

 

举例:

  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()的高级版~

 

例子:

  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. }  

信号集

 

 

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

 

举例:

  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、内核只会保存一个同类的信号,其他的都被丢掉了。

 

 

一、文件锁

    文件锁用于多个用户共同使用或操作同一个文件。有读锁的时候可以再加读锁,不能再加写锁。有写锁的时候,不能加任何锁,加读锁时,该描述符必须是读打开,加写锁时,该描述符必须是写打开,且只在进程间有用。     

 

 重写的上锁方法

  1. //lock.c   
  2. int lock_set(int fd,int type){  
  3.     struct flock lock;  
  4.   
  5.     lock.l_type=type;  
  6.     lock.l_start=0;  
  7.     lock.l_whence=SEEK_SET;  
  8.     lock.l_len = 0;  
  9.     lock.l_pid=-1;  
  10.   
  11.     fcntl(fd,F_GETLK,&lock);  
  12.     if(lock.l_type!=F_UNLCK){  
  13.         if(lock.l_type == F_RDLCK)  
  14.             printf("Read lock already set by %d!\n",lock.l_pid);  
  15.         else if(lock.l_type == F_WRLCK)  
  16.             printf("Write lock already set by %d!\n",lock.l_pid);  
  17.     }  
  18.     lock.l_type = type;  
  19.     //此处的F_SETLKW为F_SETLK的阻塞版本,当无法获取锁时进入睡眠等待状态  
  20.     if(fcntl(fd,F_SETLKW,&lock)<0){  
  21.         printf("Lock failed:type=%d!\n",lock.l_type);  
  22.         exit(1);  
  23.     }  
  24.   
  25.     switch(lock.l_type){  
  26.         case F_RDLCK:  
  27.             printf("read lock set by %d\n",getpid());  
  28.             break;  
  29.         case F_WRLCK:  
  30.             printf("write lock set by %d\n",getpid());  
  31.             break;  
  32.         case F_UNLCK:  
  33.             printf("UN lock set by %d\n",getpid());  
  34.             break;  
  35.         default:  
  36.             break;  
  37.     }  
  38. }  

上写锁

  1. #include<stdio.h>   
  2. #include<fcntl.h>   
  3. #include<unistd.h>
      
  4. #include"lock.c"   
  5.   
  6. int main(){  
  7.     int fd;  
  8.     fd=open("readme",O_RDWR|O_CREAT,0666);  
  9.     if(fd<0){  
  10.         printf("Open file error\n");  
  11.         exit(1);  
  12.     }  
  13.     lock_set(fd,F_WRLCK);  
  14.     getchar();  
  15.     lock_set(fd,F_UNLCK);  
  16.     getchar();  
  17.     return 0;  
  18.   
  19. }  

上读锁

  1. #include<stdio.h>   
  2. #include<fcntl.h>   
  3. #include<unistd.h>
      
  4. #include"lock.c"   
  5.   
  6. int main(){  
  7.     int fd;  
  8.     fd=open("readme",O_RDWR|O_CREAT,0666);  
  9.     if(fd<0){  
  10.         printf("Open file error\n");  
  11.         exit(1);  
  12.     }  
  13.     lock_set(fd,F_RDLCK);  
  14.     getchar();  
  15.     lock_set(fd,F_UNLCK);  
  16.     getchar();  
  17.     return 0;  
  18.   
  19. }  

在两个终端中测试:

两个终端可以同时加上读锁。

有一个终端加上读锁,则必须等读锁释放才能加写锁。

有一个终端加写锁必须释放才能加别的锁。

 

二、多路复用:select、poll

  1. #include<stdio.h>   
  2. #include<fcntl.h>   
  3. #include<unistd.h>
      
  4. #include<memory.h>   
  5. #define MAX(a,b) (a>b?a:b)  
  6.   
  7. int main(){  
  8.     int fd[3];  
  9.     char buff[1024];  
  10.     int res,max_fd,i,num;  
  11.     fd_set insert,temp_insert;  
  12.     struct timeval tv;  
  13.     fd[0]=0;  
  14.     if((fd[1]=open("in1",O_RDONLY|O_NONBLOCK))<0){  
  15.         printf("open in1 error!\n");  
  16.         return 1;  
  17.     }  
  18.     if((fd[2]=open("in2",O_RDONLY|O_NONBLOCK))<0){  
  19.         printf("open in2 error!\n");  
  20.         return 1;  
  21.     }  
  22.     //选出最大的fd,select()函数用的   
  23.     max_fd=MAX(MAX(fd[0],fd[1]),fd[2]);  
  24.     //清空fd_set   
  25.     FD_ZERO(&insert);  
  26.     for(i=0;i<3;i++){  
  27.         FD_SET(fd[i],&insert);  
  28.     }  
  29.     //设置延迟   
  30.     tv.tv_sec=60;  
  31.     tv.tv_usec=0;  
  32.   
  33.     while(FD_ISSET(fd[0],&insert) || FD_ISSET(fd[1],&insert) || FD_ISSET(fd[2],&insert)){  
  34.         temp_insert = insert;  
  35.         //select函数会对fd_set产生修改,只保存变化的文件符,所以要用一个temp  
  36.         res=select(max_fd+1,&temp_insert,NULL,NULL,&tv);  
  37.         switch(res){  
  38.             case -1:  
  39.                     printf("select error!\n");  
  40.                     return 1;  
  41.                     break;  
  42.             case 0:  
  43.                     printf("time out\n");  
  44.                     return 1;  
  45.                     break;  
  46.             default:  
  47.                     for(i=0;i<3;i++){  
  48.                         if(FD_ISSET(fd[i],&temp_insert)){  
  49.                                 memset(buff,0,1024);  
  50.                                 num=read(fd[i],buff,1024);  
  51.                                 if(num<0){  
  52.                                     return 1;  
  53.                                 }else if(num == 0){  
  54.                                     close(fd[i]);  
  55.                                     FD_CLR(fd[i],&insert);  
  56.                                 }else{  
  57.                                     if(i == 0){  
  58.                                         if((buff[0] == 'q') || (buff[0] == 'Q')){  
  59.                                             return 0;  
  60.                                         }  
  61.                                     }  
  62.                                     write(STDOUT_FILENO,buff,num);  
  63.   
  64.                                 }  
  65.                         }  
  66.                     }  
  67.             }  
  68.     }  
  69. }  

 

poll用法与select很相似,只是在一些变量上有些不同:

 

  1. #include <unistd.h>   
  2. #include <fcntl.h>   
  3. #include <time.h>
      
  4. #include <stdio.h>   
  5. #include <stdlib.h>
      
  6. #include <string.h>   
  7. #include <poll.h>
      
  8.   
  9. #define MAX_BUFFER_SIZE 1024  
  10. #define IO_IN_FILES 3   
  11. #define TIME_DELAY 60000
      
  12.   
  13. int main() {  
  14.     struct pollfd fds[IO_IN_FILES];  
  15.     char buff[MAX_BUFFER_SIZE];  
  16.     int i,res,real_read;  
  17.   
  18.     fds[0].fd=0;  
  19.     if((fds[1].fd=open("in1",O_RDONLY|O_NONBLOCK))<0) {  
  20.         printf("Open in1 error!\n");  
  21.         return 1;  
  22.     }  
  23.       
  24.     if((fds[2].fd=open("in2",O_RDONLY|O_NONBLOCK))<0) {  
  25.         printf("Open in2 error!\n");  
  26.         return 1;  
  27.     }  
  28.   
  29.     for(i=0;i<IO_IN_FILES;i++)  
  30.         fds[i].events=POLLIN;  
  31.       
  32.     while(fds[0].events||fds[1].events||fds[2].events) {  
  33.         res=poll(fds,IO_IN_FILES,TIME_DELAY);  
  34.   
  35.         switch(res) {  
  36.             case -1:  
  37.                 printf("POLL error!\n");  
  38.                 return 1;  
  39.                 break;  
  40.             case 0:  
  41.                 printf("Time out!\n");  
  42.                 return 1;  
  43.                 break;  
  44.             default:  
  45.                 for(i=0;i<IO_IN_FILES;i++) {  
  46.                     if(fds[i].revents) {  
  47.                         memset(buff,0,MAX_BUFFER_SIZE);  
  48.                         real_read=read(fds[i].fd,buff,MAX_BUFFER_SIZE);  
  49.                         if(real_read<0){  
  50.                             printf("Read error!\n");  
  51.                             return 1;  
  52.                         } else if (real_read==0) {  
  53.                             close(fds[i].fd);  
  54.                             fds[i].events=0;  
  55.                         } else {  
  56.                             if (i==0) {  
  57.                                 if((buff[0]=='q')||(buff[0]=='Q'))  
  58.                                     return 0;  
  59.                             } else {  
  60.                                 write(STDOUT_FILENO, buff,real_read);  
  61.                             //  buff[real_read]='\0';  
  62.                             //  printf("%s",buff);  
  63.                             }  
  64.                         }  
  65.                               
  66.                     }  
  67.   
  68.                 }  
  69.         }  
  70.     }     
  71.       
  72.     return 0;  
  73. }  

 

抱歉!评论已关闭.