[Linux]进程控制

1. 进程创建

在这里插入图片描述

  • 代码测试
  1 #include <stdio.h>                                                                                    
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 
  5 int main()
  6 {
  7     pid_t pid = fork();
  8     if (pid < 0)
  9     {
 10         perror("fork error\n");
 11         return -1;
 12     }
 13 
 14     else if (pid == 0)
 15     {
 16         printf("子进程创建成功[%d]\n", getpid());
 17         // 只有子进程才会进入
 18     }
 19     else if (pid > 0)
 20     {
 21         printf("父进程创建成功[%d]\n", getpid());
 22         // 只有父进程才能进入
 23     }
 24     printf("父子进程都能进入[%d]\n", getpid());
 25     return 0;
 26 }             
  • 结果
[test@localhost ForkTest]$ make
gcc fork.c -o fork
[test@localhost ForkTest]$ ./fork 
父进程创建成功[7368]
父子进程都能进入[7368]
子进程创建成功[7369]
父子进程都能进入[7369]

2. 进程终止

在这里插入图片描述

3. 进程等待

  • 当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。僵尸进程会导致资源泄露.
  • 当父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源
  • 进程等待的意义: 等待一个子进程的退出, 获取退出子进程的返回值, 并且释放子进程资源, 防止出现僵尸进程
  • 一旦出现僵尸进程, 那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程
  • 僵尸进程示例代码
#include <stdio.h>                                                                                  
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 
 int main()
 {
     pid_t pid = fork();
     if (pid < 0)
     {
         perror("fork error");
         exit(-1);
     }
     else if (pid == 0)
     {
         sleep(5);
         exit(0);
     }
     while(1)
     {
         printf("打LOL~~~\n");
         sleep(1);
     }
 
     return 0;
 }     
           
  • 运行结果

运行后立刻查看当前信息

[test@localhost ~]$ ps -aux|grep wait
test       8272  0.0  0.0   4216   352 pts/0    S+   18:17   0:00 ./wait
test       8273  0.0  0.0   4212    84 pts/0    S+   18:17   0:00 ./wait

5秒钟后查看当前信息

[test@localhost ~]$ ps -aux|grep wait
test       8272  0.0  0.0   4216   352 pts/0    S+   18:17   0:00 ./wait
test       8273  0.0  0.0      0     0 pts/0    Z+   18:17   0:00 [wait] <defunct>
  • 通过进程等待的操作即可防止僵尸进程
  • 使用wait()来进行进程等待
 #include <stdio.h>                                                                                  
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 
 int main()
 {
     pid_t pid = fork();
     if (pid < 0)
     {
         perror("fork error");
         exit(-1);
     }
     else if (pid == 0)
     {
         sleep(5);
         exit(0);
     }
     // 添加wait();
     wait(NULL);
     while(1)
     {
         printf("打LOL~~~\n");
         sleep(1);
     }
 
     return 0;
 }     
           
  • 进程等待的两个操作
    在这里插入图片描述

  • 使用waitpid()先不对status进行探讨;

int main()
{
     pid_t pid = fork();
     if (pid < 0)
     {
         perror("fork error");
         exit(-1);
     }
     else if (pid == 0)
     {
         sleep(5);
         exit(0);                                                                                    
     }
     // wait(NULL);
     
     // int ret = waitpid(-1, NULL, 0);
     
     // 使用非阻塞
     // int ret = waitpid(-1, NULL, WNOHANG);
     // 使用非阻塞此时还会产生僵尸进程, 故非阻塞的操作一般需要循环操作
     while(waitpid(-1, NULL, WNOHANG) == 0)
     {
         printf("再等等\n");
         sleep(1);
     }
     // 由于之前的循环操作子进程已经释放了
     // 那么下面得到的ret就应该是为负数, 没有子进程出错
     int ret = waitpid(-1, NULL, WNOHANG);
                                                                                                     
     if (ret < 0)
     {
         perror("waitpid error");
     }
     else if(ret == 0)
     {
         printf("have no child exit\n");
     }
     else
     {
         printf("pid:%d child exited\n", getpid());
     }
     while(1)
     {
         printf("打LOL~~~\n");
         sleep(1);
     }
 
     return 0;
}            

  • 结果
gcc wait.c -o wait
[test@localhost ForkTest]$ ./wait
再等等
再等等
再等等
再等等
再等等
waitpid error: No child processes
打LOL~~~
打LOL~~~
打LOL~~~
打LOL~~~
打LOL~~~
  • 使用status保存信息
    在这里插入图片描述
#include <stdio.h>                                                                                  
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
 
int main()
{
     pid_t pid = fork();
     if (pid < 0)
     {
         perror("fork error");
         exit(-1);
     }
     else if (pid == 0)
     {
         sleep(5);
         exit(99);
     } 
    // wait(NULL);
     
     // int ret = waitpid(-1, NULL, 0);
     
     // 使用非阻塞
     // int ret = waitpid(-1, NULL, WNOHANG);
     // 使用非阻塞此时还会产生僵尸进程, 故非阻塞的操作一般需要循环操作
     int status = -1;
     while(waitpid(-1, &status, WNOHANG) == 0)
     {
         printf("再等等\n");
         sleep(1);
     }                                                                                               
     // 操作系统提供了WIFEXITED和WEXITSTATUS两个宏来对status进行操作
     // 使用宏来判断和查看
     if (WIFEXITED(status))
     {
         printf("child exit retval:%d\n", WEXITSTATUS(status));
    }
     // 和上边的宏功能相同
     if (!(status & 0x7f))
     {
         printf("child exit retval:%d\n", (status) >> 8 & 0x0ff);
     }
     else
     {
         printf("process occured exception\n");
     }
     // 由于之前的循环操作子进程已经释放了
     // 那么下面得到的ret就应该是为负数, 没有子进程出错
     int ret = waitpid(-1, NULL, WNOHANG);                                                           
 
     if (ret < 0)
     {
         perror("waitpid error");
     }
    else if(ret == 0)
     {
         printf("have no child exit\n");
     }
     else
     {
         printf("pid:%d child exited\n", getpid());
     }
     while(1)
     {
         printf("打LOL~~~\n");
         sleep(1);                                                                                   
     }
 
     return 0;
}

  • 执行结果
[test@localhost ForkTest]$ ./wait
再等等
再等等
再等等
再等等
再等等
child exit retval:99
child exit retval:99
waitpid error: No child processes
打LOL~~~
打LOL~~~
打LOL~~~
^C

4. 进程程序替换

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数 以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

在这里插入图片描述
在这里插入图片描述

  • 程序替换功能十分强大
  • 一般是让父进程创建子进程, 让子进程来替换

5. 实现minishell

发布了53 篇原创文章 · 获赞 46 · 访问量 7213

猜你喜欢

转载自blog.csdn.net/new_bee_01/article/details/103878535