I/O 进程 7.2

前言

今天是7月3日,补昨天进程的内容。

概述

1.基础

2.代码演示

3.练习

1.基础

一、进程五态图

  1. 状态转换流程

    创建态 → 就绪态 → 运行态 → 终止态 ↖______↙ 阻塞态

    • 触发条件

      • 就绪态 → 运行态:获取CPU资源

      • 运行态 → 阻塞态:等待I/O或资源

      • 阻塞态 → 就绪态:资源就绪

  2. 进程ID关系

    • 层级结构SID (Session ID) > PGID (Group ID) > PPID (Parent PID) > PID

    • 父子进程流:进程间形成树状依赖关系。

    • 特殊ID

      • 0:引导进程

      • 1:init进程(接收孤儿进程)

      • 2:内核进程


二、进程查看指令

| 指令 | 功能描述 |
|------------------|-----------------|-------------|
| `ps -qix | grep a.out` | 查看特定进程的详细信息 |
| ps -qyx | 显示所有进程(含线程) |
| pstree -p PPID | 以树状图显示PPID下的进程树 |
| pidof a.out | 获取进程的PID |
| kill -q PID | 结束指定PID的进程 |

注意事项

  • 查看进程时需保持权限限制。

  • 使用pstree可直观分析进程层级关系。


三、进程操作函数

  1. 创建进程

    pid_t fork(void);

    • 返回值

      • 父进程返回子进程PID

      • 子进程返回0

    • 特点:子进程复制父进程的地址空间。

  2. 退出进程

    void exit(int status);

    • 状态码

      • EXIT_SUCCESS(0):正常退出

      • EXIT_FAILURE(非0):异常退出

  3. 获取进程ID

    pid_t getpid(void); // 当前进程PID

    pid_t getppid(void); // 父进程PID

  4. 回收子进程

    pid_t wait(int *wstatus);

    pid_t waitpid(pid_t pid, int *wstatus, int options);

    • 功能:阻塞父进程,直到子进程退出。

四、关键概念补充

  1. 进程地址空间

    • fork()后子进程继承父进程的地址空间副本,通过写时复制(Copy-On-Write)优化。
  2. 阻塞与非阻塞

    • 阻塞调用 :如wait(),进程暂停直至条件满足。

    • 非阻塞:需结合轮询或信号机制。

  3. 孤儿进程

    • 父进程先终止时,子进程由init进程(PID=1)接管。

五、思维导图与笔记

2.代码演示

2.1 增:fork

cpp 复制代码
#include <IO_head.h>
int main(int argc, const char* argv[]){
    pid_t pid = fork();
    printf("pid = %d\n", pid);

    if(pid==0){
        printf("son\n");
    }
    if(pid>0){
        //sleep(1);
        printf("father\n");
    }
    if(pid==-1){
        ERROR("fork failed");
    }

    return 0;
}
bash 复制代码
ubuntu@ubuntu:~/IO/class3$ ./01_fork 
pid = 25767
father
pid = 0
son

2.2 删:exit

cpp 复制代码
#include <IO_head.h>
int main(int argc, const char* argv[]){
    //main函数也是进程,此处main作为父进程
    pid_t pid = fork();     //创建子进程
    //子进程:由fork函数返回
    if(pid>0){
        printf("pid = %d, ppid = %d, _%d_\n",getpid(),getppid(),__LINE__);
        //getpid,getppid获取执行该语句的进程的pid,ppid
        while(1){
            //由于父进程占用了cpu资源,所以会打印
            printf("father process\n");
            sleep(1);
        }
    }

    else if(pid==0){
        printf("pid = %d, ppid = %d, _%d_\n",getpid(),getppid(),__LINE__);
        exit(0);

        //fflush(stdout);
        //_exit

        while(1){
            //没资源,不打印
            printf("son process\n");
            sleep(1);
        }
    }

    else{ERROR("");}

    while(1);
    return 0;
}
bash 复制代码
ubuntu@ubuntu:~/IO/class3$ ./02_exit 
pid = 25817, ppid = 23303, _7_
father process
pid = 25818, ppid = 25817, _16_
father process
father process
father process
father process
father process
^C

2.3 回收

cpp 复制代码
#include <IO_head.h>
int main(int argc, const char* argv[]){
    pid_t pid = fork();

    if(pid>0){
        //用status接收waitpid返回的子进程的退出值
        int status;
        waitpid(-1,&status,0);  //注意wait和waitpid会阻塞函数

        printf("father process\n");

        //printf("status = %d\n",(status&0xff)>>8);
        printf("status = %d\n",WEXITSTATUS(status));
    }

    else if(pid==0){
        exit(EXIT_FAILURE);
        //exit(EXIT_SUCCESS);
        //exit(3);
        //0:EXIT_SUCCESS;非0:EXIT_FAILURE
    }

    else{ERROR("");}

    while(1);
    return 0;
}
bash 复制代码
ubuntu@ubuntu:~/IO/class3$ ./03_wait 
father process
status = 3
^C

2.4 僵尸进程

cpp 复制代码
#include <IO_head.h>
//若不回收子进程的资源,则成为僵尸进程
int main(int argc,const char* argv[]){
    pid_t pid = fork();

    if(pid>0){
        while(1){
            printf("father process\n");
            sleep(1);
        }
    }else if(pid==0){
        printf("son process\n");
        exit(0);
    }
    else{ERROR("");}

    return 0;
}
bash 复制代码
ubuntu@ubuntu:~/IO/class4$ ./02_zombie 

ubuntu@ubuntu:~/IO/class4$ ps -ajx | grep 02_zombie
   3203    8410    8410    3203 pts/1       8410 S+    1000   0:00 ./02_zombie
   8410    8411    8410    3203 pts/1       8410 Z+    1000   0:00 [02_zombie] <defunct>
   8360    8474    8473    8360 pts/2       8473 S+    1000   0:00 grep --color=auto 02_zombie
ubuntu@ubuntu:~/IO/class4$ 

2.5 守护进程

cpp 复制代码
#include <IO_head.h>
//1.创建孤儿进程
int main(int argc,const char* argv[]){
    pid_t pid = fork();

    if(pid==0){
        //2.设置新会话
        setsid();

        //3.把路径修改为根目录
        chdir("/tmp");

        //4写入
        umask(0);

        int guard_file_des = open("/tmp/my.txt", O_RDWR|O_APPEND|O_CREAT, 0777);

        //4.2重新定向三个自带流指针
        dup2(guard_file_des,0);
        dup2(guard_file_des,1);
        dup2(guard_file_des,2);

        //4.1关闭3-1024576
        for(int i = 3; i<getdtablesize(); ++i){
            close(i);
        }


        while(1){
            printf("son process\n");//写入
            fflush(stdout); //刷新缓冲区
            sleep(1);
        }
    }
    else if(pid==-1){ERROR("");}
    else if(pid>0){exit(0);}

    return 0;
}

3.练习

补充:流程图

3.1扇形进程

cpp 复制代码
#include <IO_head.h>
int main(int argc, const char* argv[]){
    for(int i=0; i<=3; ++i){
        pid_t pid = fork();
        if(pid == -1){
            ERROR("");
        }else if(pid==0){   //son
            printf("son process with id:%d\n",getpid());
            break;  //防止子进程继续繁殖
        }else if(pid>0){    //father
            NULL;
        }
    }
    while(1);
    return 0;
}
bash 复制代码
ubuntu@ubuntu:~/IO/class3$ ps -ajx|grep h1_fan
  23303   23659   23659   23303 pts/3      23659 R+    1000   0:41 ./h1_fan
  23659   23660   23659   23303 pts/3      23659 R+    1000   0:41 ./h1_fan
  23659   23661   23659   23303 pts/3      23659 R+    1000   0:41 ./h1_fan
  23659   23662   23659   23303 pts/3      23659 R+    1000   0:41 ./h1_fan
  23659   23663   23659   23303 pts/3      23659 R+    1000   0:41 ./h1_fan
  23607   23840   23839   23607 pts/1      23839 S+    1000   0:00 grep --color=auto h1_fan
ubuntu@ubuntu:~/IO/class3$ pstree -p 23659
h1_fan(23659)─┬─h1_fan(23660)
              ├─h1_fan(23661)
              ├─h1_fan(23662)
              └─h1_fan(23663)

3.2 链进程

cpp 复制代码
#include <IO_head.h>
int main(int argc, const char* argv[]){
    pid_t pid;
    for(int i=0; i<=3; ++i){
        pid = fork();
        if(pid==-1){
            ERROR("");
        }else if(pid==0){   //son
            printf("son process with id:%d\n",getpid());
            NULL;   //接着循环就行。
            //把父进程阻塞了,子进程自然成了父进程,继续繁殖
        }else if(pid>0){    //father
            wait(NULL); //不能闭掉,因为闭掉子就也没了
            //进入阻塞态是正确的。
            exit(0);    //跳出阻塞说明循环完了,回收一下资源
        }
    }

    while(1);
    return 0;
}
bash 复制代码
ubuntu@ubuntu:~/IO/class3$ ps -ajx|grep h2_lincked
  23303   24172   24172   23303 pts/3      24172 S+    1000   0:00 ./h2_lincked
  24172   24173   24172   23303 pts/3      24172 S+    1000   0:00 ./h2_lincked
  24173   24174   24172   23303 pts/3      24172 S+    1000   0:00 ./h2_lincked
  24174   24175   24172   23303 pts/3      24172 S+    1000   0:00 ./h2_lincked
  24175   24176   24172   23303 pts/3      24172 R+    1000   0:22 ./h2_lincked
  23607   24292   24291   23607 pts/1      24291 S+    1000   0:00 grep --color=auto h2_lincked
ubuntu@ubuntu:~/IO/class3$ pstree -p 24172
h2_lincked(24172)───h2_lincked(24173)───h2_lincked(24174)───h2_lincked(24175)─+++
ubuntu@ubuntu:~/IO/class3$ pstree -p 23303
bash(23303)───h2_lincked(24172)───h2_lincked(24173)───h2_lincked(24174)───h2_lincked(24175)───h2+

3.3 分进程拷贝文件

cpp 复制代码
#include <IO_head.h>
void RD_WR(int start, int end, int ori_des, int new_des){
    lseek(ori_des, start, SEEK_SET);
    lseek(new_des, start, SEEK_SET);
    char buf;
    for(int i = start; i<end;++i){
        read(ori_des, &buf, 1);
        write(new_des, &buf, 1);
    }
    printf("copy succeeded\n");
}


int main(int argc, const char* argv[]){
    //文件IO:文件描述符
    int file_ori_des = open("./01_fork.c",O_RDONLY);
    int file_new_des = open("./01_new_fork.c",O_WRONLY|O_CREAT|O_TRUNC,0777);

    int len = lseek(file_ori_des,0,SEEK_END);

    pid_t pid = fork();
    if(pid>0){  //父进程
        //sleep(1);
        wait(NULL);
        RD_WR(0,len/2,file_ori_des,file_new_des);     
    }else if(pid==0){ 
        RD_WR(len/2,len,file_ori_des,file_new_des);      //子进程
        exit(0);
    }else if(pid==-1){      //error
        ERROR("");
    }

    return 0;
}

结语

以上

相关推荐
水木兰亭2 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
M4K02 小时前
Linux百度网盘优化三板斧
linux
好奇的菜鸟2 小时前
如何在 Ubuntu 24.04 (Noble) 上使用阿里源
linux·运维·ubuntu
Jess073 小时前
插入排序的简单介绍
数据结构·算法·排序算法
老一岁3 小时前
选择排序算法详解
数据结构·算法·排序算法
xindafu3 小时前
代码随想录算法训练营第四十二天|动态规划part9
算法·动态规划
bcbobo21cn3 小时前
初步了解Linux etc/profile文件
linux·运维·服务器·shell·profile
xindafu3 小时前
代码随想录算法训练营第四十五天|动态规划part12
算法·动态规划
望获linux3 小时前
【实时Linux实战系列】CPU 隔离与屏蔽技术
java·linux·运维·服务器·操作系统·开源软件·嵌入式软件
0wioiw03 小时前
C#基础(项目结构和编译运行)
linux·运维·服务器