• OS | Process


    linux多进程

    1. fork()创建进程,创建一份父进程的拷贝;在父进程中返回的是子进程id,在子进程中返回的是0;失败时返回-1;

    2. fork()经常和exec()结合,exec() 覆盖了原进程的空间,转而执行其他程序;

    3. 杀掉父进程,不会同时杀掉子进程;

    孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

    僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这个子进程称之为僵尸进程。系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。孤儿进程并不会有什么危害。

    当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。

    避免zombie的方法:

    • 忽略信号SIGCHLD, signal(SIGCHLD,SIG_IGN); 
    • 父进程中调用wait或waitpid;
    • 调用两次fork();父进程一次fork()后产生一个子进程随后立即执行waitpid(子进程pid, NULL, 0)来等待子进程结束,然后子进程fork()后产生孙子进程随后立即exit(0)。这样子进程顺利终止(父进程仅仅给子进程收尸,并不需要子进程的返回值),然后父进程继续执行。这时的孙子进程由于失去了它的父进程(即是父进程的子进程),将被转交给Init进程托管。于是父进程与孙子进程无继承关系了,它们的父进程均为Init,Init进程在其子进程结束时会自动收尸,这样也就不会产生僵尸进程了。ddkkk
     1 #include <stdio.h>  
     2 #include <stdlib.h>  
     3 #include <sys/wait.h>  
     4 #include <sys/types.h>  
     5 #include <unistd.h>  
     6 
     7 int main() {     
     8     pid_t pid;     
     9 
    10     if ((pid = fork()) < 0) {     
    11         fprintf(stderr,"Fork error!
    ");     
    12         exit(-1);     
    13     } else if (pid == 0) { // child 
    14         if ((pid = fork()) < 0) {      
    15             fprintf(stderr,"Fork error!
    ");     
    16             exit(-1);     
    17         } else if (pid > 0) {    
    18             printf("child: %d, parent pid = %d
    ", getpid(), getppid());     
    19             exit(0); // child exit   
    20         } else {
    21             printf("grandchild: %d, parent pid = %d
    ", getpid(), getppid());     
    22             exit(0);
    23         }
    24     } else {
    25         printf("pid: %d
    ", getpid());
    26         if (waitpid(pid, NULL, 0) != pid) {     
    27             fprintf(stderr,"Waitpid error!
    ");     
    28             exit(-1);     
    29         }     
    30         return 0; 
    31     }
    32 }     

    输出为:

    1 root@xxj-VirtualBox:~/interview# ./process 
    2 pid: 7411
    3 child: 7412, parent pid = 7411
    4 root@xxj-VirtualBox:~/interview# grandchild: 7413, parent pid = 1755
    5 
    6 root@xxj-VirtualBox:~/interview# ps ax|grep 1755
    7  1755 ?        Ss     0:00 init --user
    8  7415 pts/3    S+     0:00 grep --color=auto 1755

    父进程是7411,子进程的父进程是7411没错,孙进程是7413,现在它被init进程(1755)回收了。

    打印父进程的父进程发现是5976,5976是bash的pid。

    4. wait() 等待子进程;可以获取子进程的返回状态;

    5. system()就是用fork()+exec()+wait()实现;

    6. execlp(),每一个是可执行文件的路径,第二个参数开始就是arg0,arg1,...,所以arg0必须就是可执行文件名,最后一个arg必须是NULL; 

     1 int main() {
     2     int pid = fork();
     3     if (pid < 0) {
     4         fprintf(stderr, "fork failed");
     5         return -1;
     6     } else if (pid == 0) {
     7         cout << "child process" << endl;
     8         execlp("/bin/touch", "touch", "/root/lab/os/1", NULL);    
     9     } else {
    10         cout << "pid of child:" << pid << endl;
    11         int status;
    12         wait(&status);
    13         cout << "status of child:" << status << endl;
    14     }
    15     return 0;
    16 }

     共享内存通信

    1. shm_open打开或者创建共享内存object,名字必须以/开头;一开始大小为0;需要通过ftruncate()设置大小;

    2. 用mmap将shared memory object映射到内存;映射为MAP_SHARED,这样在其他进程中可见;即使进程退出了,在没有调用shm_unlink之前,其他进程还是可以访问这一块区域的。

     1 #include <sys/mman.h>
     2 #include <sys/stat.h>        
     3 #include <fcntl.h>          
     4 #include <stdio.h>
     5 #include <unistd.h>
     6 #include <sys/types.h>
     7 
     8 int main() {
     9     int shmID = shm_open("/test", O_CREAT | O_RDWR, 0666);
    10     if (shmID < 0) {
    11         fprintf(stderr, "shm create failed
    ");
    12         return -1;
    13     }
    14     ftruncate(shmID, 2014);
    15     char* p = (char*)mmap(NULL, 2014, PROT_WRITE, MAP_SHARED, shmID, 0);
    16     for (int i = 0; i < 2000; i++) {
    17         p[i] = '0' + i % 10;
    18     }
    19     munmap(p, 2014);
    20     return 0;
    21 }
     1 #include <stdio.h>
     2 #include <sys/mman.h>
     3 #include <sys/stat.h>       
     4 #include <fcntl.h>         
     5 
     6 int main() {
     7     int shmID = shm_open("/test", O_RDONLY, 0666);
     8     if (shmID < 0) {
     9         fprintf(stderr, "shm open fail
    ");
    10         return -1;
    11     }
    12     char* p = (char*)mmap(NULL, 2014, PROT_READ, MAP_SHARED, shmID, 0);
    13     if (p == NULL) {
    14         return -1;
    15     }
    16     for (int i = 0; i < 100; i++) {
    17         printf("%c ", p[i]);
    18     }
    19     printf("
    ");
    20 
    21     shm_unlink("/test");
    22     munmap(p, 2014);
    23     return 0;
    24 }
  • 相关阅读:
    Asp.net 连接池使用
    关于ASP.NET页面打印技术的总结
    Asp.net页面传值总结
    C#委托
    ASP.NET状态存储管理九大兵器
    JavaScript取ASP.NET中服务器端数据的方法
    DSOFramer.ocx 控件使用
    C#2.0 泛型学习(入门)
    黑马程序员——Java基础String与StringBuilder
    黑马程序员——Java基础语法关键字、常量、变量、运算符
  • 原文地址:https://www.cnblogs.com/linyx/p/3805165.html
Copyright © 2020-2023  润新知