
❀保持低旋律节奏->个人主页

文章目录
-
- 一、什么是进程?
- [二、 为什么要存在进程?](#二、 为什么要存在进程?)
- 三、如何通过代码管理进程?
-
- 系统调用函数
-
- 3.1第一个系统调用------getpid函数
- 3.2查看进程
-
- [3.2.1TTY 终端](#3.2.1TTY 终端)
- 3.3cwd获取当前路径
- 3.4bash
- 四、fork()函数
一、什么是进程?
进程得概念
进程=程序本身得代码和数据+操作系统内核对应的数据结构
进程可以是正在被执行的程序、可以是被加载到内存里的程序
但是进程统一特点是运行的程序
1.1进程控制块PCB
所有进程它所对应的 数据结构和结构体 都能在操作系统内核里面找到。
而每一个进程它所对应的结构体叫做 进程控制块------PCB
进程控制块里面 存在程序它所对应的结构 和属性
这些属性包括
| PCB(struct_task)属性 |
|---|
| 标识符:PID |
| 状态 |
| 优先级 |
| 程序计数器 |
| 内存指针:指向实实在在的代码 |
| 上下文数据 |
| I/O状态信息 |
| 记账信息(功能类似日志) |
1.2.进程的管理
每个程序操作系统内核当中都能找到它们所对应的数据结构------PCB,PCB里面包含程序所有属性,以及结构体。而这些所有的PCB默认是以链表的形式链接在一起。
因此操作系统对进程的管理->操作系统对链表的增删查改
二、 为什么要存在进程?
所有的指令执行、工具执行、程序执行 都必须转化为进程
我们再Windows下 所有通过双击打开的东西 都是进程
进程就是用户想要做什么、进程就是用户的意志!
三、如何通过代码管理进程?
PCB存在于操作系统内核部分,而用户没有直接访问操作系统内核的权限。
因此有且仅有唯一的办法访问操作系统内核------系统调用
系统调用函数
3.1第一个系统调用------getpid函数
man getpid
getpid 的使用需要包含头文件
#include <sys/types.h>
#include <unistd.h>
c
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 pid_t id = getpid();
10 printf("pid:%d\n",id);
11 sleep(1);
12 }
13 return 0;
14 }
执行结果

3.2查看进程
查看进行有两种形式
- 第一种是再根目录下访问 proc文件
- 第二种使用ps命令
第一种访问方法
cd /
less/head/ls proc
bash
[ljy@VM-0-12-centos /]$ ls proc
1 15173 24 386 615 execdomains net
10 1588 25 4 616 fb pagetypeinfo
1007 16 252 411 617 filesystems partitions
1072 16081 26 4119 618 fs sched_debug
1074 1731 262 4126 619 interrupts schedstat
1077 17617 265 4127 620 iomem scsi
109 18 266 413 65 ioports self
11 18583 267 46 7 irq slabinfo
12 19 26876 48 7031 kallsyms softirqs
1242 19364 27 49 8 kcore stat
1246 19377 270 50 9 keys swaps
1255 199 271 51 acpi key-users sys
1256 2 28 522 buddyinfo kmsg sysrq-trigger
1286 20 287 5338 bus kpagecount sysvipc
1288 20098 29 5353 cgroups kpageflags timer_list
1289 20109 291 5423 cmdline loadavg timer_stats
1298 2013 292 5424 consoles locks tty
13 21 3359 588 cpuinfo mdstat uptime
14 22 3479 593 crypto meminfo version
14695 23 35 595 devices misc vmallocinfo
14714 23304 36 596 diskstats modules vmstat
14953 23315 37 6 dma mounts xpmem
14993 23856 38 600 driver mtrr zoneinfo
第二种访问方法!推荐
ps ajx
bash
[ljy@VM-0-12-centos 12-12]$ ps ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 32:01 /usr/lib/systemd/sys
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 4 0 0 ? -1 S< 0 0:00 [kworker/0:0H]
2 6 0 0 ? -1 S 0 0:34 [ksoftirqd/0]
2 7 0 0 ? -1 S 0 0:06 [migration/0]
2 8 0 0 ? -1 S 0 0:00 [rcu_bh]
2 9 0 0 ? -1 S 0 4:48 [rcu_sched]
2 10 0 0 ? -1 S< 0 0:00 [lru-add-drain]
2 11 0 0 ? -1 S 0 0:02 [watchdog/0]
2 12 0 0 ? -1 S 0 0:02 [watchdog/1]
2 13 0 0 ? -1 S 0 0:06 [migration/1]
2 14 0 0 ? -1 S 0 0:29 [ksoftirqd/1]
2 16 0 0 ? -1 S< 0 0:00 [kworker/1:0H]
2 18 0 0 ? -1 S 0 0:00 [kdevtmpfs]
2 19 0 0 ? -1 S< 0 0:00 [netns]
2 20 0 0 ? -1 S 0 0:00 [khungtaskd]
2 21 0 0 ? -1 S< 0 0:00 [writeback]
2 22 0 0 ? -1 S< 0 0:00 [kintegrityd]
2 23 0 0 ? -1 S< 0 0:00 [bioset]
2 24 0 0 ? -1 S< 0 0:00 [bioset]
2 25 0 0 ? -1 S< 0 0:00 [bioset]
2 26 0 0 ? -1 S< 0 0:00 [kblockd]
2 27 0 0 ? -1 S< 0 0:00 [md]
2 28 0 0 ? -1 S< 0 0:00 [edac-poller]
2 29 0 0 ? -1 S< 0 0:00 [watchdogd]
2 35 0 0 ? -1 S 0 0:00 [kswapd0]
2 36 0 0 ? -1 SN 0 0:00 [ksmd]
2 37 0 0 ? -1 SN 0 0:01 [khugepaged]
2 38 0 0 ? -1 S< 0 0:00 [crypto]
2 46 0 0 ? -1 S< 0 0:00 [kthrotld]
2 48 0 0 ? -1 S< 0 0:00 [kmpath_rdacd]
2 49 0 0 ? -1 S< 0 0:00 [kaluad]
2 50 0 0 ? -1 S< 0 0:00 [kpsmoused]
2 51 0 0 ? -1 S< 0 0:00 [ipv6_addrconf]
2 65 0 0 ? -1 S< 0 0:00 [deferwq]
2 109 0 0 ? -1 S 0 0:04 [kauditd]
2 199 0 0 ? -1 S< 0 0:00 [iscsi_eh]
2 252 0 0 ? -1 S< 0 0:00 [ata_sff]
2 262 0 0 ? -1 S 0 0:00 [scsi_eh_0]
2 265 0 0 ? -1 S< 0 0:00 [scsi_tmf_0]
2 266 0 0 ? -1 S 0 0:00 [scsi_eh_1]
2 267 0 0 ? -1 S< 0 0:00 [scsi_tmf_1]
2 270 0 0 ? -1 S< 0 0:00 [ttm_swap]
2 271 0 0 ? -1 S< 0 0:06 [kworker/1:1H]
2 287 0 0 ? -1 S< 0 0:38 [kworker/0:1H]
2 291 0 0 ? -1 S 0 1:53 [jbd2/vda1-8]
2 292 0 0 ? -1 S< 0 0:00 [ext4-rsv-conver]
1 386 386 386 ? -1 Ss 0 0:20 /usr/lib/systemd/sys
1 411 411 411 ? -1 Ss 0 0:00 /usr/sbin/lvmetad -f
1 413 413 413 ? -1 Ss 0 0:00 /usr/lib/systemd/sys
1 522 522 522 ? -1 S<sl 0 0:07 /sbin/auditd
1 588 588 588 ? -1 Ss 0 0:26 /usr/lib/systemd/sys
1 593 593 593 ? -1 Ss 998 0:03 /usr/bin/lsmd -d
1 595 595 595 ? -1 Ssl 999 0:22 /usr/lib/polkit-1/po
1 596 596 596 ? -1 Ss 81 1:02 /usr/bin/dbus-daemon
1 600 600 600 ? -1 Ss 0 0:00 /usr/sbin/acpid
2 615 0 0 ? -1 S< 0 0:00 [ib-comp-wq]
2 616 0 0 ? -1 S< 0 0:00 [kworker/u5:0]
2 617 0 0 ? -1 S< 0 0:00 [ib-comp-unb-wq]
2 618 0 0 ? -1 S< 0 0:00 [ib_mcast]
2 619 0 0 ? -1 S< 0 0:00 [ib_nl_sa_wq]
2 620 0 0 ? -1 S< 0 0:00 [mlx5_ib_sigerr_]
1 1007 1007 1007 ? -1 Ss 0 0:00 /sbin/dhclient -q -l
1 1072 1072 1072 ? -1 Ssl 0 1:13 /usr/bin/python2 -Es
1 1074 1074 1074 ? -1 S<Ls 0 0:00 /sbin/iscsid -f
1 1077 1077 1077 ? -1 Ssl 0 0:00 /usr/sbin/rshim
1 1242 1242 1242 ? -1 Ssl 0 0:42 /usr/sbin/rsyslogd -
1 1246 1246 1246 ? -1 Ss 0 0:00 /usr/sbin/sshd -D
1 1255 1255 1255 ? -1 Ss 0 0:05 /usr/sbin/crond -n
1 1256 1256 1256 ? -1 Ss 0 0:00 /usr/sbin/atd -f
1 1286 1286 1286 ? -1 Ss 0 0:03 /usr/libexec/postfix
1 1288 1288 1288 tty1 1288 Ss+ 0 0:00 /sbin/agetty --nocle
1 1289 1289 1289 ttyS0 1289 Ss+ 0 0:00 /sbin/agetty --keep-
1286 1298 1286 1286 ? -1 S 89 0:00 qmgr -l -t unix -u
1 1588 1586 1586 ? -1 Sl 0 0:06 /usr/local/qcloud/st
1 1731 1729 1729 ? -1 Sl 0 2:11 /usr/local/qcloud/ta
1 2013 2013 2013 ? -1 Ss 38 0:01 /usr/sbin/ntpd -u nt
1 3359 1374 1374 ? -1 Sl 0 221:27 /usr/local/qcloud/Yu
1 3479 1374 1374 ? -1 Sl 0 5:45 /usr/local/qcloud/Yu
1 4119 4118 4118 ? -1 S 0 0:05 barad_agent
4119 4126 4118 4118 ? -1 S 0 5:51 barad_agent
4119 4127 4118 4118 ? -1 Sl 0 64:20 barad_agent
1246 5338 5338 5338 ? -1 Ds 0 0:00 sshd: root@pts/0
5338 5353 5353 5353 pts/0 19231 Ss 0 0:00 -bash
5353 5423 5423 5353 pts/0 19231 S 0 0:00 su - ljy
5423 5424 5424 5353 pts/0 19231 S 1001 0:00 -bash
1286 7031 1286 1286 ? -1 S 89 0:00 pickup -l -t unix -u
1 14695 14695 14695 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
1 14714 14714 14714 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
2 14993 0 0 ? -1 S 0 0:00 [kworker/u4:1]
2 15173 0 0 ? -1 S 0 0:00 [kworker/1:0]
2 16081 0 0 ? -1 S 0 0:00 [kworker/0:0]
2 17617 0 0 ? -1 S 0 0:00 [kworker/0:2]
2 18770 0 0 ? -1 R 0 0:00 [kworker/0:1]
5424 19231 19231 5353 pts/0 19231 R+ 1001 0:00 ps ajx
1 19364 19364 19364 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
1 19377 19377 19377 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
1 20098 20098 20098 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
1 20109 20109 20109 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
1 23304 23304 23304 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
1 23315 23315 23315 ? -1 Ssl 1001 0:00 /home/ljy/.VimForCpp
2 23856 0 0 ? -1 S 0 0:01 [kworker/1:1]
2 26876 0 0 ? -1 S 0 0:05 [kworker/u4:2]
ps + 管道 +grep
ljy 用户 执行proc.exe 得到进程号 22292
root 用户查看 进程号2292所有程序
bash
[root@VM-0-12-centos ~] ps ajx | head -1 && ps ajx | grep 22292

3.2.1TTY 终端
echo "aaa" > /dev/pts/0
发现可以向终端发送数据

3.3cwd获取当前路径
c
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 char buf[1024];
8 while(1)
9 {
10 pid_t id = getpid();
11 printf("pid:%d\n",id);
12 getcwd(buf,sizeof(buf));
13 printf("getcwdL%s\n",buf);
14 sleep(1);
15 }
16 return 0;
17 }

3.4bash
每一次登录系统都会自动提供bash来对命令行服务
bash 是命令解释器、本身也是进程 它是一个死循环
四、fork()函数
c
1 #include<stdio.h>
2 #include<unistd.h> //fork()\getpid()\getppid()头文件
3 #include<sys/wait.h> //wait头文件
4 #include<stdlib.h> //exit()头文件
5
6 int main()
7 {
8
9 //1.打印父进程的初始信息
10 printf("----父进程的初始信息----\n");
11 printf("父进程PID:%d,父进程PPID:%d\n",getpid(),getppid());
12 printf("--------------------\n");
13
14 //2.调用fork()创建子进程
15 pid_t pid = fork();
16 //3.处理错误:fork()失败
17 if(pid ==-1)
18 {
19 perror("fork调用失败"); //打印错误原因
20 exit(EXIT_FAILURE);
21 }
22 //4.子进程逻辑 (fork()返回0)
23 else if (pid == 0)
24 {
25 printf("----子进程执行逻辑----\n");
26 printf("子进程PID:%d\n",getpid());
27 printf("子进程中fork()返回值:%d\n",pid);
28 printf("--------------------\n");
29 printf("所有程序执行完毕\n");
30 }
31 //5.父进程的执行逻辑(fork()返回子进程的PID)
32 else
33 {
34 //等待子进程执行完毕,避免父进程先退出导致子进程编程孤儿进程
35 wait(NULL);
36 printf("----父进程后续逻辑----\n");
37 printf("父进程PID:%d\n",getpid());
38 printf("父进程中fork()返回值:%d\n",pid);
39 printf("--------------------\n");
40 printf("所有程序执行完毕\n");
41
42 }
43 return 0;
44 }
执行结果
c
----父进程的初始信息----
父进程PID:16422,父进程PPID:25886
--------------------
----子进程执行逻辑----
子进程PID:16423
子进程中fork()返回值:0
--------------------
所有程序执行完毕
----父进程后续逻辑----
父进程PID:16422
父进程中fork()返回值:16423
--------------------
所有程序执行完毕
👍fork三个问题
那么我们通过代码头次接触fork会存在诸多问题。下面就挑选几个核心问题然后进行解答
- 1.fork之后为什么给子进程返回0,给父进程返回子进程的pid?
父进程需要子进程 PID:便于管理多个子进程(如waitpid等待指定子进程、kill给指定子进程发信号);
子进程返回 0:0 是永远不会被分配给真实进程的特殊值,用于快速标识 "当前进程是子进程"(子进程可通过getppid()获取父进程 PID);
失败时统一返回 - 1,作为创建失败的唯一标识。
- 2.同一函数为什么能被返回2次?
pid_t id = fork()是系统调用函数,那么它在if else if else分支中理应只能执行其中一个分支。那么为什么id技能==0又能>0呢?
fork 调用触发内核复制出子进程,父子进程成为两个独立的执行流;内核给两个执行流的id分别赋值(子进程 id=0、父进程 id = 子进程 PID);最终两个进程各自执行 if/else 分支,仅走其中一个分支 ------ 从程序员视角看,表现为 "一次调用,两次返回"。
本质是因为它们是两个独立的执行流
- 3.同一变量id为什么即==0又>0?
因为id是两个独立进程中拥有相同虚拟地址的不同物理变量
本质是两个id不是同一个变量(实现方法 虚拟内存+写实拷贝)
最终精简版(可直接用)
对的!本质是两个 id 不是同一个变量;其中「虚拟内存的地址映射」是实现 "同虚拟地址、不同物理变量" 的核心机制,而写时拷贝(COW)是 fork 过程中减少内存拷贝的高效优化手段,二者共同保障了这个逻辑的实现。

