目录
3.5、查看进程
[HJM@hjmlcc ~]$ clear
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ ls
[HJM@hjmlcc ~]$ touch mytest.c
[HJM@hjmlcc ~]$ ls
mytest.c
[HJM@hjmlcc ~]$ touch Makefile
[HJM@hjmlcc ~]$ ls
Makefile mytest.c
[HJM@hjmlcc ~]$ vim Makefile
[HJM@hjmlcc ~]$ cat Makefile
mytest:mytest.c
gcc mytest.c -o mytest
.PHONY:clean
clean:
rm -f mytest
[HJM@hjmlcc ~]$ vim mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1) //死循环、
{
printf("I am a process!\n");
sleep(1);
}
return 0;
}
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
//此处的 mytest 是可执行程序,是一个普通文件,存在于磁盘上,该磁盘指的并不是在我们笔记本中的磁
//盘上,而是存在于云服务器上的磁盘中、
[HJM@hjmlcc ~]$ ldd mytest
linux-vdso.so.1 => (0x00007ffcba19d000)
/$LIB/libonion.so => /lib64/libonion.so (0x00007f18b638f000)
libc.so.6 => /lib64/libc.so.6 (0x00007f18b5ea8000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f18b5ca4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f18b6276000)
[HJM@hjmlcc ~]$ file mytest
mytest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=e1ce1242da6edeb0fd0c5a1c316cbd303ba05c73, not stripped
[HJM@hjmlcc ~]$ ./mytest
//之前我们称上述操作为将可执行程序mytest运行起来,现在通过上述操作便可形成一个进程,因此我们可
//以称上述操作是:一个关于可执行程序mytest所形成的进程、
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
...
...
在 Linux 操作系统中,如何查看正在运行(时实启动)的进程及其信息呢?
方法一:
[HJM@hjmlcc ~]$ clear
[HJM@hjmlcc ~]$ ps ajx //a:all,j:job,x:以特定格式进行显示,或者是: ps axj ,顺序无所谓、
//把 Linux 操作系统中所有的正在运行的时实启动的进程及其信息全部显示出来、
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 17:46 /usr/lib/sys
0 2 0 0 ? -1 S 0 0:03 [kthreadd]
2 4 0 0 ? -1 S< 0 0:00 [kworker/0:0
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:02 [khungtaskd]
...
...
2 30148 0 0 ? -1 S 0 0:00 [kworker/0:1
1 30373 30373 30373 ? -1 Ssl 1002 0:00 /home/HJM/.V
1 30380 30380 30380 ? -1 Ssl 1002 0:00 /home/HJM/.V
30380 30391 30380 30380 ? -1 Z 1002 0:00 [querydb] <d
1 31068 31068 31068 ? -1 Ssl 1002 0:00 /home/HJM/.V
1 31076 31076 31076 ? -1 Ssl 1002 0:00 /home/HJM/.V
31076 31087 31076 31076 ? -1 Z 1002 0:00 [querydb] <d
2 31438 0 0 ? -1 S 0 0:00 [kworker/0:3
2 32544 0 0 ? -1 S 0 0:01 [kworker/0:0
[HJM@hjmlcc ~]$ ps ajx | grep 'mytest'
10484 12399 12399 10484 pts/0 12399 S+ 1002 0:00 ./mytest
12404 13061 13060 12404 pts/1 13060 S+ 1002 0:00 grep --color=automytest
//在Linux操作系统中所有的正在运行的时实启动的进程及其信息中查找关于可执行程序mytest所形成的
//进程及其信息,若关于可执行程序mytest所形成的进程正在运行或时实启动,则会把关于可执行程序mytes
//t所形成的进程及其信息显式出来,若关于可执行程序mytest所形成的进程未正在运行或未时实启动,则
//不会把关于可执行程序mytest所形成的进程及其信息显式出来、
//对于上述指令行而言,有关可执行程序ps所形成的进程和有关可执行程序grep所形成的进程一直都是在
//运行(时实启动)的,有关可执行程序mytest所形成的进程可能正在运行(时实启动),也有可能没有正在运
//行(时实启动),由于上面是对有关可执行程序mytest形成的进程及其信息进行的搜索,按理说只需要显式
//出来有关可执行程序mytest形成的进程是否正在运行(时实启动)即可,但此处还把正在运行(时实启动)
//的有关可执行程序grep所形成的进程及其信息显示了出来,其次,虽然这里并未显式出来正在运行(时实
//启动的)有关可执行程序ps所形成的进程及其信息,但要知道,有关可执行程序ps所形成的进程一直正在
//运行(时实启动),只不过这里并没有把该进程及其信息显式出来而已,由于此处还默认显式出来正在运行
//(时实启动的)有关可执行程序grep所形成的进程及其信息,若不想显式该进程及其信息的话,可以通过下
//述操作:
[HJM@hjmlcc ~]$ ps ajx | grep 'mytest' | grep -v grep
//即:上述操作中grep -v的后面只要匹配到某一个有关某一个可执行程序所形成的进程所对应的可执行程
//序的名字,则该进程及其信息一律不进行显式,此时我们知道,对于有关可执行程序grep所形成的进程而
//言是一直在运行(时实启动)的,按理说在下面会显示出来该进程及其信息,但是,上述操作中又有grep -v
// grep,所以在下面结果中就不再进行显示该进程及其信息了、
10484 23680 23680 10484 pts/0 23680 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$
我们自己写的程序代码,当经过编译链接之后则形成一个可执行程序,运行该可执行程序之后就得到一个进程,同样,别人写的程序代码当编译链接之后也会形成一个可执行程序,运行该可执行程序之后也得到一个进程,比如:ls,pwd,touch,grep,chgrp,chown,mkdir,rm ... 等等指令,这些指令在本质上就是可执行程序,当我们执行这些指令时,本质上就是运行了这些可执行程序,因此当运行这些可执行程序时,也会得到这些可执行程序各自对应的进程,Linux 系统中的大部分指令(可执行程序)存在于云服务器中的磁盘里面,可以通过指令:ls /usr/bin/* 查看,如下所示,这些大部分指令(可执行程序)就等价于 Windows 系统中 C 盘里的应用程序(可执行程序)、
[HJM@hjmlcc ~]$ ls /usr/bin/*
//usr:用户,bin:二进制、
/usr/bin/[
/usr/bin/a2p
/usr/bin/abrt-action-analyze-backtrace
/usr/bin/abrt-action-analyze-c
/usr/bin/abrt-action-analyze-ccpp-local
/usr/bin/abrt-action-analyze-core
/usr/bin/abrt-action-analyze-oops
/usr/bin/abrt-action-analyze-python
/usr/bin/abrt-action-analyze-vmcore
/usr/bin/abrt-action-analyze-vulnerability
/usr/bin/abrt-action-analyze-xorg
/usr/bin/abrt-action-check-oops-for-hw-err
...
...
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo
/usr/bin/zipnote
/usr/bin/zipsplit
/usr/bin/zless
/usr/bin/zmore
/usr/bin/znew
/usr/bin/zsoelim
[HJM@hjmlcc ~]$
//之前我们执行的所有的指令,本质上都是在运行可执行程序,则都会形成这些可执行程序对应的进程,只不
//过像:ls,pwd等等这些指令,在执行时,也相当于在运行可执行程序,因此则都会形成他们对应的进程,但
//是他们对应的进程的生命周期很短就结束了,即当我执行完这些指令时,由这些指令所形成的进程很快就
//结束了,在我通过方法查看正在运行或时实启动的进程及其信息之前,由这些指令所形成的进程就已经结
//束了,所以当在查看正在运行或时实启动的进程及其信息时,就看不到由这些指令所形成的进程及其信
//息了、
//在 Windows 系统中,当我们双击 CF 的快捷方式,而该快捷方式指向了 CF 的可执行程序,所以就相当
//于在双击 CF 的可执行程序,即就相当于在运行 CF 的可执行程序,因此便形成了一个与它对应的进程,
//就可以愉快的玩游戏了、
方法二:
操作系统是进程的管理者,每一个正在运行(时实启动)的进程在 Linux 操作系统中都会存在唯一的一个与之对应的标识符,这个唯一的标识符就是所谓的 PID ,即:Process ID 、
[HJM@hjmlcc ~]$ ps ajx | grep 'mytest'
12404 3406 3405 12404 pts/1 3405 S+ 1002 0:00 grep --color=auto mytest
10484 31395 31395 10484 pts/0 31395 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$ ps ajx | grep 'mytest' | grep -v grep
10484 31395 31395 10484 pts/0 31395 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$ ps ajx | head -1 //是1不是l,代表前1行、
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
[HJM@hjmlcc ~]$ ps ajx | head -5
//把 Linux 操作系统中所有的正在运行的时实启动的进程及其信息的前 5 行全部显示出来,其中第一行
//代表进程属性的名称、
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 17:59 /usr/lib/systemd/systemd --system --deserialize 23
0 2 0 0 ? -1 S 0 0:03 [kthreadd]
2 4 0 0 ? -1 S< 0 0:00 [kworker/0:0H]
2 6 0 0 ? -1 S 0 2:20 [ksoftirqd/0]
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
//当指令行:ps ajx | head -1执行成功后,再执行指令行:head -1 && ps ajx | grep 'mytest' | grep
// -v grep,若前面的指令行执行失败,则后面的指令行就不再进行执行了、
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10484 31395 31395 10484 pts/0 31395 S+ 1002 0:00 ./mytest
//由此可知,有关可执行程序mytest所形成的进程的 PID 是31395、
[HJM@hjmlcc ~]$ ls /proc/31395
attr cmdline environ io mem ns pagemap sched stack task
autogroup comm exe limits mountinfo numa_maps patch_state schedstat stat timers
auxv coredump_filter fd loginuid mounts oom_adj personality sessionid statm uid_map
cgroup cpuset fdinfo map_files mountstats oom_score projid_map setgroups status wchan
clear_refs cwd gid_map maps net oom_score_adj root smaps syscall
[HJM@hjmlcc ~]$ ls /proc/31395 -d
/proc/31395
//此时如果把有关可执行程序mytest所形成的进程结束掉,然后再执行指令:ls /proc/31395 -d时,得到
//如下结果,这是因为,根目录下的proc目录中存放的是当前 Linux 操作系统中正在运行或时实启动的进
//程及其信息、
[HJM@hjmlcc ~]$ ls /proc/31395 -d
ls: cannot access /proc/31395: No such file or directory
[HJM@hjmlcc ~]$
//当把有关可执行程序mytest所形成的进程再次启动时,若再执行上述指令:ls /proc/31395 -d,会发现
//得到的结果是:ls: cannot access /proc/31395: No such file or directory,如下所示:
[HJM@hjmlcc ~]$ ls /proc/31395 -d
ls: cannot access /proc/31395: No such file or directory
[HJM@hjmlcc ~]$ ps ajx | grep 'mytest' | grep -v grep
10484 27073 27073 10484 pts/0 27073 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10484 27073 27073 10484 pts/0 27073 S+ 1002 0:00 ./mytest
//这是因为:当我们重新启动有关可执行程序mytest所形成的进程时,此次的该进程与前一次启动有关可执行
//程序mytest所形成的进程并不是同一个进程,后者相对于前者而言是一个新的进程,所以此次的有关可执
//行程序mytest所形成的进程的 PID 也会发生改变,Linux 操作系统会为其重新分配 PID ,由31395变成
//了27073、
[HJM@hjmlcc ~]$ ls /proc/27073 -d
/proc/27073
[HJM@hjmlcc ~]$ ls /proc/27073
//以下则是有关可执行程序mytest所形成的进程的所有的属性数据信息的集合,时实的以文件的方式进行
//显示、
attr cmdline environ io mem ns pagemap sched stack task
autogroup comm exe limits mountinfo numa_maps patch_state schedstat stat timers
auxv coredump_filter fd loginuid mounts oom_adj personality sessionid statm uid_map
cgroup cpuset fdinfo map_files mountstats oom_score projid_map setgroups status wchan
clear_refs cwd gid_map maps net oom_score_adj root smaps syscall
[HJM@hjmlcc ~]$ ls /proc/27073 -al
total 0
dr-xr-xr-x 9 HJM HJM 0 Nov 12 19:09 .
dr-xr-xr-x 124 root root 0 Jul 28 11:13 ..
dr-xr-xr-x 2 HJM HJM 0 Nov 12 19:15 attr
-rw-r--r-- 1 HJM HJM 0 Nov 12 19:15 autogroup
-r-------- 1 HJM HJM 0 Nov 12 19:15 auxv
-r--r--r-- 1 HJM HJM 0 Nov 12 19:15 cgroup
--w------- 1 HJM HJM 0 Nov 12 19:15 clear_refs
-r--r--r-- 1 HJM HJM 0 Nov 12 19:09 cmdline
-rw-r--r-- 1 HJM HJM 0 Nov 12 19:15 comm
-rw-r--r-- 1 HJM HJM 0 Nov 12 19:15 coredump_filter
-r--r--r-- 1 HJM HJM 0 Nov 12 19:15 cpuset
lrwxrwxrwx 1 HJM HJM 0 Nov 12 19:09 cwd -> /home/HJM
//上述代表有关可执行程序mytest所形成的的进程当前的工作路径、
-r-------- 1 HJM HJM 0 Nov 12 19:09 environ
lrwxrwxrwx 1 HJM HJM 0 Nov 12 19:09 exe -> /home/HJM/mytest
//上述代表的就是有关可执行程序mytest所形成的的进程对应的在云服务器中的磁盘中的可执行程序mytes
//t所在的路径、
...
...
-r--r--r-- 1 HJM HJM 0 Nov 12 19:15 statm
-r--r--r-- 1 HJM HJM 0 Nov 12 19:09 status
-r--r--r-- 1 HJM HJM 0 Nov 12 19:15 syscall
dr-xr-xr-x 3 HJM HJM 0 Nov 12 19:15 task
-r--r--r-- 1 HJM HJM 0 Nov 12 19:15 timers
-rw-r--r-- 1 HJM HJM 0 Nov 12 19:15 uid_map
-r--r--r-- 1 HJM HJM 0 Nov 12 19:15 wchan
[HJM@hjmlcc ~]$
//进程的 PID 以及当前路径等等都属于进程的属性数据信息,都属于系统数据,都在描述该进程的进程控
//制块(PCB),在 Linux 系统下的 task_struct 结构体中、
//在之前,我们认为当前路径就是程序或者源代码所在的路径,其实本质上并不准确,真正意义上的当前路径
//指的就是:进程当前所在(工作)的路径,当进程启动时,这个路径由进程自己进行维护、
//如下所示:
//新建会话0:
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<unistd.h>
int main()
{
FILE* fp=fopen("log.txt","w");
//由此可知,log.txt前面并没有指定路径,则默认为当前路径下,如果在当前路径下不存在普通文
//件log.txt,则会新建一个名为log.txt的普通文件、
while(1)
{
printf("I am a process!\n");
sleep(1);
}
return 0;
}
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
code Makefile mytest mytest.c
[HJM@hjmlcc ~]$ mv mytest code
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cd code
[HJM@hjmlcc code]$ ls
mytest
[HJM@hjmlcc code]$ ./mytest
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
...
...
//新建会话1:
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cd code
[HJM@hjmlcc code]$ ls
mytest
[HJM@hjmlcc code]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10484 1738 1738 10484 pts/0 1738 S+ 1002 0:00 ./mytest
[HJM@hjmlcc code]$ ls /proc/1738
attr environ mem pagemap stack
autogroup exe mountinfo patch_state stat
auxv fd mounts personality statm
cgroup fdinfo mountstats projid_map status
clear_refs gid_map net root syscall
cmdline io ns sched task
comm limits numa_maps schedstat timers
coredump_filter loginuid oom_adj sessionid uid_map
cpuset map_files oom_score setgroups wchan
cwd maps oom_score_adj smaps
[HJM@hjmlcc code]$ ls /proc/1738 -d
/proc/1738
[HJM@hjmlcc code]$ ls /proc/1738 -al
total 0
dr-xr-xr-x 9 HJM HJM 0 Nov 12 19:44 .
dr-xr-xr-x 126 root root 0 Jul 28 11:13 ..
dr-xr-xr-x 2 HJM HJM 0 Nov 12 19:45 attrer
-r--r--r-- 1 HJM HJM 0 Nov 12 19:45 cpuset
lrwxrwxrwx 1 HJM HJM 0 Nov 12 19:44 cwd -> /home/HJM/code //当前路径、
-r-------- 1 HJM HJM 0 Nov 12 19:45 environ
lrwxrwxrwx 1 HJM HJM 0 Nov 12 19:44 exe -> /home/HJM/code/mytest
lrwxrwxrwx 1 HJM HJM 0 Nov 12 19:44 root -> /
-rw-r--r-- 1 HJM HJM 0 Nov 12 19:45 sched
...
...
-r--r--r-- 1 HJM HJM 0 Nov 12 19:45 syscall
dr-xr-xr-x 3 HJM HJM 0 Nov 12 19:45 task
-r--r--r-- 1 HJM HJM 0 Nov 12 19:45 timers
-rw-r--r-- 1 HJM HJM 0 Nov 12 19:45 uid_map
-r--r--r-- 1 HJM HJM 0 Nov 12 19:45 wchan
[HJM@hjmlcc ~]$
//新建会话0:
...
...
I am a process!
I am a process!
I am a process!
I am a process!
I am a process!
^C
[HJM@hjmlcc code]$ ls
log.txt mytest
//注意:
//1、
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cd code
[HJM@hjmlcc code]$ ls
[HJM@hjmlcc code]$ cd ..
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
code Makefile mytest mytest.c
[HJM@hjmlcc ~]$ make clean
rm -f mytest
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$
//2、
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cd code
[HJM@hjmlcc code]$ ls
[HJM@hjmlcc code]$ cd ..
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
code Makefile mytest mytest.c
[HJM@hjmlcc ~]$ mv mytest code
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cd code
[HJM@hjmlcc code]$ ls
mytest
[HJM@hjmlcc code]$ make clean
make: *** No rule to make target `clean'. Stop. //无法删除可执行程序mytest、
[HJM@hjmlcc code]$ cd ..
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ make clean
rm -f mytest
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ cd code
[HJM@hjmlcc code]$ ls
mytest //仍没有删除掉可执行程序mytest、
[HJM@hjmlcc code]$
//在讲解粘滞位时,tmp目录文件是一个共享的目录文件,里面存放的是临时文件、
//proc目录文件是 Linux 系统根目录下的一个目录,proc:process,proc:内存文件系统,该目录文件中存
//放的是当前操作系统中正在运行或时实运行的进程及其信息、
[HJM@hjmlcc ~]$ ls /
bin boot data dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[HJM@hjmlcc ~]$
[HJM@hjmlcc ~]$ ls /
bin boot data dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[HJM@hjmlcc ~]$ ls /proc
1 12535 16515 20344 25287 28 31335 50 7 cpuinfo irq modules swaps
10 13 16526 20730 255 29 31368 51 8 crypto kallsyms mounts sys
10470 1389 16792 20827 256 290 36 52 8227 devices kcore mtrr sysrq-trigger
10483 1390 18 21 26 291 37 577 9 diskstats keys net sysvipc
10484 14 18820 21813 262 292 3756 6 925 dma key-users pagetypeinfo timer_list
11 1521 18853 22 266 29633 38 646 991 driver kmsg partitions timer_stats
1164 1552 19 23 267 30123 387 648 993 execdomains kpagecount sched_debug tty
1178 1558 19039 24 269 30373 3871 65 acpi fb kpageflags schedstat uptime
12 1559 19089 24315 27 30380 39 651 buddyinfo filesystems loadavg scsi version
1207 1575 197 2472 270 30391 4 6515 bus fs locks self vmallocinfo
1222 16 2 2485 27176 31068 407 652 cgroups interrupts mdstat slabinfo vmstat
12404 160 20 2496 27184 31076 47 654 cmdline iomem meminfo softirqs xpmem
12524 16503 20337 25 27195 31087 49 659 consoles ioports misc stat zoneinfo
[HJM@hjmlcc ~]$ ls /proc -l
total 0
dr-xr-xr-x 9 root root 0 Jul 28 11:13 1
dr-xr-xr-x 9 root root 0 Jul 28 11:13 10
dr-xr-xr-x 9 root root 0 Nov 12 14:59 10470
dr-xr-xr-x 9 HJM HJM 0 Nov 12 14:59 10483
dr-xr-xr-x 9 HJM HJM 0 Nov 12 14:59 10484
dr-xr-xr-x 9 root root 0 Jul 28 11:13 11
dr-xr-xr-x 9 root root 0 Jul 28 11:13 1164
dr-xr-xr-x 9 root root 0 Jul 28 11:13 1178
dr-xr-xr-x 9 root root 0 Jul 28 11:13 12
dr-xr-xr-x 9 root root 0 Jul 28 11:13 1207
dr-xr-xr-x 9 root root 0 Jul 28 11:13 8
dr-xr-xr-x 9 root root 0 Nov 12 14:48 8227
dr-xr-xr-x 9 root root 0 Jul 28 11:13 9
dr-xr-xr-x 9 root root 0 Jul 28 11:13 925
dr-xr-xr-x 9 root root 0 Jul 28 11:13 991
dr-xr-xr-x 9 root root 0 Jul 28 11:13 993
dr-xr-xr-x 2 root root 0 Nov 12 16:47 acpi
-r--r--r-- 1 root root 0 Nov 12 16:47 buddyinfo
dr-xr-xr-x 4 root root 0 Nov 12 16:47 bus
-r--r--r-- 1 root root 0 Nov 12 16:47 cgroups
-r--r--r-- 1 root root 0 Nov 12 16:47 cmdline
-r--r--r-- 1 root root 0 Nov 12 16:47 consoles
-r--r--r-- 1 root root 0 Nov 12 16:47 cpuinfo
-r--r--r-- 1 root root 0 Nov 12 16:47 crypto
-r--r--r-- 1 root root 0 Nov 12 16:47 devices
...
...
-r--r--r-- 1 root root 0 Nov 12 16:47 version
-r-------- 1 root root 0 Nov 12 16:47 vmallocinfo
-r--r--r-- 1 root root 0 Nov 12 16:47 vmstat
dr-xr-xr-x 2 root root 0 Nov 12 16:47 xpmem
-r--r--r-- 1 root root 0 Nov 12 16:47 zoneinfo
[HJM@hjmlcc ~]$
方法三:
//一、
//新建会话0:
[HJM@hjmlcc ~]$ ls
a.out lcc.c Makefile process process.c
[HJM@hjmlcc ~]$ ./process
I am a process:9684
I am a process:9684
I am a process:9684
I am a process:9684
I am a process:9684
...
...
//新建会话1: //a,u,x三者的顺序无所谓、
[HJM@hjmlcc ~]$ ls
a.out lcc.c Makefile process process.c
[HJM@hjmlcc ~]$ ps aux | head -1 && ps aux | grep 'process' | grep -v grep
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
HJM 9684 0.0 0.0 7332 380 pts/0 S+ 17:31 0:00 ./process
[HJM@hjmlcc ~]$
//2、
//新建会话0:
...
...
I am a process:9684
I am a process:9684
I am a process:9684
I am a process:9684
^C
[HJM@hjmlcc ~]$
//新建会话1:
[HJM@hjmlcc ~]$ ls
a.out lcc.c Makefile process process.c
[HJM@hjmlcc ~]$ ps aux | head -1 && ps aux | grep 'process' | grep -v grep
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
[HJM@hjmlcc ~]$
拓展:
[HJM@hjmlcc ~]$ pwd /home/HJM [HJM@hjmlcc ~]$ ls //显式出当前路径(目录)下的所有内容、 Makefile mytest mytest.c [HJM@hjmlcc ~]$ ls / //此处的 / 代表根目录、 //显示出根目录下的所有内容、 bin boot data dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [HJM@hjmlcc ~]$ ls /proc //此处的 / 代表根目录、 //显示出根目录下的proc目录中的所有内容、 1 12535 16515 20344 25287 28 36 52 7 cpuinfo irq modules swaps 10 13 16526 20730 255 29 37 577 8 crypto kallsyms mounts sys 10470 1389 16792 20827 256 290 3756 6 8227 devices kcore mtrr sysrq-trigger 10483 1390 18 21 26 291 38 646 9 diskstats keys net sysvipc 10484 14 18820 21813 262 292 387 648 925 dma key-users pagetypeinfo timer_list 11 1521 18853 22 266 30373 3871 65 991 driver kmsg partitions timer_stats 1164 1552 19 23 267 30380 39 650 993 execdomains kpagecount sched_debug tty 1178 1558 19039 24 269 30391 4 651 acpi fb kpageflags schedstat uptime 12 1559 19089 24315 27 31068 407 6515 buddyinfo filesystems loadavg scsi version 1207 1575 197 2472 270 31076 47 652 bus fs locks self vmallocinfo 1222 16 2 2485 27176 31087 49 654 cgroups interrupts mdstat slabinfo vmstat 12404 160 20 2496 27184 31395 50 659 cmdline iomem meminfo softirqs xpmem 12524 16503 20337 25 27195 32061 51 678 consoles ioports misc stat zoneinfo [HJM@hjmlcc ~]$ ls /home/HJM //此处只有第一个 / 代表根目录、 //显示出根目录下的home目录下的HJM目录中的所有内容、 Makefile mytest mytest.c [HJM@hjmlcc ~]$ // cd 指令的用法也类似于上面所示、
3.6、通过系统调用接口获取时实进程的标识符
通过Linux操作系统所提供的系统调用接口获取正在进行(时实启动)的进程的进程ID(PID)和该进程的父进程ID(PPID)、
如何获取正在运行(时实启动)的进程的 PID 呢 ?
//当启动一个进程,则该进程就是正在运行(时实启动)的,则操作系统会为该进程分配一个 PID 、
[HJM@hjmlcc ~]$ man 2 getpid //查看Linux操作系统提供的系统调用接口、
//由于Linux操作系统是使用C语言写的,故Linux操作系统所提供的系统调用接口在本质上就是C语言函数
//调用接口,这属于Linux操作系统的系统调用接口,在Windows系统下使用该Linux系统下的该系统调用
//接口,应该是不可以的、
GETPID(2) Linux Programmer's Manual GETPID(2)
NAME
getpid, getppid - get process identification
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); // pid_t 等价于 size_t 、
pid_t getppid(void);
DESCRIPTION
getpid() returns the process ID of the calling process. (This is often used by routines that generate unique temporary filenames.)
getppid() returns the process ID of the parent of the calling process.
ERRORS
These functions are always successful.
CONFORMING TO
POSIX.1-2001, 4.3BSD, SVr4.
NOTES
Since glibc version 2.3.4, the glibc wrapper function for getpid() caches PIDs, so as to avoid additional system calls when a process calls
getpid() repeatedly. Normally this caching is invisible, but its correct operation relies on support in the wrapper functions for fork(2),
vfork(2), and clone(2): if an application bypasses the glibc wrappers for these system calls by using syscall(2), then a call to getpid() in
the child will return the wrong value (to be precise: it will return the PID of the parent process). See also clone(2) for discussion of a
case where getpid() may return the wrong value even when invoking clone(2) via the glibc wrapper function.
SEE ALSO
clone(2), fork(2), kill(2), exec(3), mkstemp(3), tempnam(3), tmpfile(3), tmpnam(3), credentials(7)
COLOPHON
This page is part of release 3.53 of the Linux man-pages project. A description of the project, and information about reporting bugs, can be
found at http://www.kernel.org/doc/man-pages/.
Manual page getpid(2) line 1 (press h for help or q to quit)q
//新建会话0:
[HJM@hjmlcc ~]$ ls
code Makefile mytest.c
[HJM@hjmlcc ~]$ vim mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("I am a process!,pid:%d\n",getpid());
sleep(1);
}
return 0;
}
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
code Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
I am a process!,pid:9457
I am a process!,pid:9457
I am a process!,pid:9457
I am a process!,pid:9457
I am a process!,pid:9457
I am a process!,pid:9457
...
...
//新建会话1:
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
5899 9457 9457 5899 pts/0 9457 S+ 1002 0:00 ./mytest //9457、
[HJM@hjmlcc ~]$
如何结束掉正在运行(时实启动)的进程呢?
方法一:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
I am a process!,pid:10001
I am a process!,pid:10001
I am a process!,pid:10001
I am a process!,pid:10001
I am a process!,pid:10001
I am a process!,pid:10001
I am a process!,pid:10001
^C
[HJM@hjmlcc ~]$
//使用热键 ctrl+c ,即可结束掉正在运行(时实启动)的进程、
方法二:
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
I am a process!,pid:10470
I am a process!,pid:10470
I am a process!,pid:10470
I am a process!,pid:10470
...
...
//新建会话1:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ kill -9 10470
//向正在运行(时实启动)的进程发送9号信号,在后期信号中会进行具体的阐述,10470就是我们要结束掉的
//正在运行(时实启动)的进程的PID、
[HJM@hjmlcc ~]$
//新建会话0:
...
...
I am a process!,pid:10470
I am a process!,pid:10470
I am a process!,pid:10470
I am a process!,pid:10470
Killed
[HJM@hjmlcc ~]$
//此时正在运行(时实启动)的有关可执行程序mytest所形成的进程就被结束掉了、
[HJM@hjmlcc ~]$ man 2 getppid
GETPID(2) Linux Programmer's Manual GETPID(2)
NAME
getpid, getppid - get process identification
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
DESCRIPTION
getpid() returns the process ID of the calling process. (This is
often used by routines that generate unique temporary filenames.)
getppid() returns the process ID of the parent of the calling
process.
ERRORS
These functions are always successful.
CONFORMING TO
POSIX.1-2001, 4.3BSD, SVr4.
NOTES
Since glibc version 2.3.4, the glibc wrapper function for getpid()
caches PIDs, so as to avoid additional system calls when a process
calls getpid() repeatedly. Normally this caching is invisible,
but its correct operation relies on support in the wrapper func‐
tions for fork(2), vfork(2), and clone(2): if an application
bypasses the glibc wrappers for these system calls by using
syscall(2), then a call to getpid() in the child will return the
wrong value (to be precise: it will return the PID of the parent
process). See also clone(2) for discussion of a case where get‐
pid() may return the wrong value even when invoking clone(2) via
Manual page getppid(2) line 1 (press h for help or q to quit)q
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("I am a process!,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
return 0;
}
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
//有关可执行程序mytest所形成的进程的进程ID(PID)为12260,而该进程的父进程ID(PPID)为5899、
I am a process!,pid:12260,ppid:5899
I am a process!,pid:12260,ppid:5899
I am a process!,pid:12260,ppid:5899
I am a process!,pid:12260,ppid:5899
I am a process!,pid:12260,ppid:5899
...
...
//新建会话1:
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
5899 12260 12260 5899 pts/0 12260 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$
//先把本次有关可执行程序mytest所形成的进程结束掉,然后再重新启动有关可执行程序mytest所形成的
//进程:
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
//有关可执行程序mytest所形成的进程的进程ID(PID)为13359,而该进程的父进程ID(PPID)为5899、
I am a process!,pid:13359,ppid:5899
I am a process!,pid:13359,ppid:5899
I am a process!,pid:13359,ppid:5899
I am a process!,pid:13359,ppid:5899
...
...
//新建会话1:
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
5899 13359 13359 5899 pts/0 13359 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$
//由上可知,当我们每一次结束掉上一次有关可执行程序mytest所形成的进程,然后再重新启动有关可执行
//程序mytest所形成的进程时,会发现,这多个由有关可执行程序mytest所形成的进程中的进程ID(PID)都
//不相同,但是这多个由有关可执行程序mytest所形成的进程中的父进程ID(PPID)则都相同、
//不管有关可执行程序mytest所形成的进程是否正在运行(时实启动),而该进程的父进程则都是一直正在
//运行(时实启动)的、
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
I am a process!,pid:15708,ppid:5899
I am a process!,pid:15708,ppid:5899
I am a process!,pid:15708,ppid:5899
...
...
//新建会话1:
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 5899
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
5898 5899 5899 5899 pts/0 15708 Ss 1002 0:00 -bash
//上述进程的进程ID(PID)为5899,这也就是有关可执行程序mytest所形成的进程的父进程、
//几乎我们在命令行上所执行的所有的指令,包括运行我们自己编写的程序代码所形成的可执行程序,所形
//成的进程都是bash进程的子进程、
5899 15708 15708 5899 pts/0 15708 S+ 1002 0:00 ./mytest
8631 16126 16125 8631 pts/1 16125 S+ 1002 0:00 grep --color=auto5899
[HJM@hjmlcc ~]$
bash 进程和 init 进程:
bash 进程就是我们每打开一个终端后运行的第一个程序,他会捕捉你的键盘输入,看你输入了什么指令,则会解析执行对应的指令程序,在终端中运行的执行程序所对应进程默认父进程就是这个 bash 进程( 因为这些指令程序对应的进程都是这个 bash 进程创建的 )、
init 进程( 也叫1号进程,就是操作系统 )是系统内非常重要的一个管理进程,系统中只有一个这个进程( bash 进程是打开了多少终端就会运行多少个 ),进程 PID 为1、在 Centos7.6 及以上版本中,1号进程换了名字、
3.7、通过系统调用接口创建子进程 - fork 初识
创建(启动)进程有很多方法,除了我们知道的运行可执行程序从而创建(启动)一个进程之外,还可以使用 Linux 操作系统所提供的系统调用接口 fork 直接创建(启动)某一个进程的子进程、
[HJM@hjmlcc ~]$ man 2 fork
//如果成功创建(启动)了当前进程的子进程,则会把当前进程的子进程的PID的值返回给当前进程(父进程)
//的id变量中,把0返回给当前进程的子进程的id变量中,因此,此时的Linux操作系统所提供的系统调用接
//口fork有两个返回值、
//这里是查询Linux操作系统提供的系统调用接口,在本质上,fork也是一个函数,如上,他有两个返回值,在
//之前我们都没有遇到过、
FORK(2) Linux Programmer's Manual FORK(2)
NAME
fork - create a child process
SYNOPSIS
#include <unistd.h>
pid_t fork(void);
DESCRIPTION
fork() creates a new process by duplicating the calling process.
The new process, referred to as the child, is an exact duplicate
of the calling process, referred to as the parent, except for the
following points:
* The child has its own unique process ID, and this PID does not
match the ID of any existing process group (setpgid(2)).
* The child's parent process ID is the same as the parent's
process ID.
* The child does not inherit its parent's memory locks (mlock(2),
mlockall(2)).
* Process resource utilizations (getrusage(2)) and CPU time coun‐
ters (times(2)) are reset to zero in the child.
* The child's set of pending signals is initially empty (sigpend‐
ing(2)).
* The child does not inherit semaphore adjustments from its par‐
ent (semop(2)).
* The child does not inherit record locks from its parent
(fcntl(2)).
Manual page fork(2) line 1 (press h for help or q to quit)/return val
RETURN VALUE
On success, the PID of the child process is returned in the par‐
ent, and 0 is returned in the child. On failure, -1 is returned
in the parent, no child process is created, and errno is set
appropriately.
//如果成功创建(启动)了当前进程的子进程,则会把当前进程的子进程的PID的值返回给当前进程(父进程)
//的id变量中,把0返回给当前进程的子进程的id变量中,如果没有成功,则会把-1返回给当前进程(父进程)
//的id变量中,此时并没有成功创建(启动)当前进程的子进程、
ERRORS
EAGAIN fork() cannot allocate sufficient memory to copy the par‐
ent's page tables and allocate a task structure for the
child.
EAGAIN It was not possible to create a new process because the
caller's RLIMIT_NPROC resource limit was encountered. To
exceed this limit, the process must have either the
CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.
ENOMEM fork() failed to allocate the necessary kernel structures
because memory is tight.
ENOSYS fork() is not supported on this platform (for example,
hardware without a Memory-Management Unit).
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001.
NOTES
Under Linux, fork() is implemented using copy-on-write pages, so
the only penalty that it incurs is the time and memory required to
duplicate the parent's page tables, and to create a unique task
structure for the child.
Since version 2.3.3, rather than invoking the kernel's fork() sys‐
tem call, the glibc fork() wrapper that is provided as part of the
NPTL threading implementation invokes clone(2) with flags that
provide the same effect as the traditional system call. (A call
to fork() is equivalent to a call to clone(2) specifying flags as
Manual page fork(2) line 101/154 89% (press h for help or q to quit)q
[HJM@hjmlcc ~]$ ls
Makefile mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t id = fork();
printf("hello,lcc\n");
sleep(1);
return 0;
}
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
hello,lcc
hello,lcc
[HJM@hjmlcc ~]$ //打印了两次、
//这是因为:父进程和子进程共享且都会执行Linux操作系统所提供的系统调用接口fork调用处之前和之后
//的所有代码以及该系统调用接口 fork 函数体内部的所有的代码、
//例子:
[HJM@hjmlcc ~]$ ls
lcc.c Makefile mytest.c
[HJM@hjmlcc ~]$ cat lcc.c
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("321\n");
pid_t id = fork();
printf("123\n");
return 0;
}
[HJM@hjmlcc ~]$ gcc lcc.c
[HJM@hjmlcc ~]$ ls
a.out lcc.c Makefile mytest.c
[HJM@hjmlcc ~]$ ./a.out
321
123
123
[HJM@hjmlcc ~]$
[HJM@hjmlcc ~]$ ls
Makefile mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t id = fork();
printf("hello,lcc!id:%d\n",id);
sleep(1);
return 0;
}
[HJM@hjmlcc ~]$ ls
Makefile mytest.c
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
hello,lcc!id:23465
hello,lcc!id:0
[HJM@hjmlcc ~]$ ./mytest
hello,lcc!id:23812
hello,lcc!id:0
[HJM@hjmlcc ~]$ ./mytest
hello,lcc!id:23832
hello,lcc!id:0
[HJM@hjmlcc ~]$
//上述现象在讲解进程地址空间时再进行阐述、
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile mytest.c
[HJM@hjmlcc ~]$ cat mytest.c
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t id = fork();
if(id == 0)
{
//当前进程(父进程)的子进程、
while(1)
{
printf("我是子进程!,我的进程ID(PID)是:%d,我的父进程ID(PPID)是:%d\n",getpi
sleep(1);
}
}
else{
//当前进程(父进程)、
while(1)
{
printf("我是父进程!,我的进程ID(PID)是:%d,我的父进程ID(PPID)是:%d\n",getpi
sleep(1);
}
}
return 0;
}
//在C语言中,if和else不可以同时执行,且在C语言中没有可能同时存在两个或两个以上的死循环、
[HJM@hjmlcc ~]$ make
gcc mytest.c -o mytest
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ./mytest
我是父进程!,我的进程ID(PID)是:19571,我的父进程ID(PPID)是:5899
我是子进程!,我的进程ID(PID)是:19572,我的父进程ID(PPID)是:19571
我是父进程!,我的进程ID(PID)是:19571,我的父进程ID(PPID)是:5899
我是子进程!,我的进程ID(PID)是:19572,我的父进程ID(PPID)是:19571
我是父进程!,我的进程ID(PID)是:19571,我的父进程ID(PPID)是:5899
我是子进程!,我的进程ID(PID)是:19572,我的父进程ID(PPID)是:19571
我是子进程!,我的进程ID(PID)是:19572,我的父进程ID(PPID)是:19571
我是父进程!,我的进程ID(PID)是:19571,我的父进程ID(PPID)是:5899
我是子进程!,我的进程ID(PID)是:19572,我的父进程ID(PPID)是:19571
我是父进程!,我的进程ID(PID)是:19571,我的父进程ID(PPID)是:5899
我是子进程!,我的进程ID(PID)是:19572,我的父进程ID(PPID)是:19571
...
...
//新建会话1:
[HJM@hjmlcc ~]$ ls
Makefile mytest mytest.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
5899 19571 19571 5899 pts/0 19571 S+ 1002 0:00 ./mytest
19571 19572 19571 5899 pts/0 19571 S+ 1002 0:00 ./mytest
[HJM@hjmlcc ~]$
//1、
//这是因为:父进程和子进程共享且都会执行Linux操作系统所提供的系统调用接口fork调用处之前和之后
//的所有代码以及该系统调用接口 fork 函数体内部的所有的代码、
//2、
//父进程和子进程各自的id变量中的值不同,在调用Linux操作系统所提供的系统调用接口fork之后,可以
//通过父进程和子进程中各自不同的id变量中的值进行判断,让父进程和子进程分别执行不同的代码块、
补充一:
在 Linux 操作系统所提供的系统调用接口 fork 中,当成功创建(启动)某一个进程的子进程时,为什么会把当前进程的子进程的 PID 的值返回给当前进程(父进程)的 id 变量中,把 0 返回给当前进程的子进程的 id 变量中呢?
创建(启动)某一个进程的子进程本质上就是相当于在操作系统中多一个执行流来帮助我们完成一部分代码,这就叫做多进程代码,父进程比子进程一定是1 :n( n>=1,能够称其为父进程,则它至少有一个子进程 ),但是任意一个子进程有且仅有一个父进程,因此,父进程必须要有标识子进程的方案,这个方案就是当成功创建(启动)某一个进程的子进程时,把当前进程的子进程的 PID 的值返回给当前进程(父进程)的 id 变量中,而把 0 返回给当前进程的子进程的 id 变量中是因为,子进程最重要的是要知道自己被创建成功了,任意一个子进程有且仅有一个父进程,因此子进程寻找父进程的成本非常低,只需要使用 Linux 操作系统所提供的系统调用接口 getppid 即可,所以,只需要把 0 返回给当前进程的子进程的 id 变量中即可、
补充二:
在 Linux 操作系统所提供的系统调用接口 fork 的函数体中,当成功创建(启动)某一个进程的子进程时,为什么会进行两次返回操作 ?
子进程所有的属性数据信息,大部分(基本上,比如优先级,状态等等,具体有哪些会在后期再进行具体的阐述)都是从该子进程的父进程继承(拷贝)得到的,但并不都是从该子进程的父进程继承(拷贝)得到的,比如:该子进程的进程 ID(PID) 等,就不是从该子进程的父进程继承(拷贝)得到的、
子进程被创建(启动)出来就是为了执行代码,计算数据的,那么该子进程的代码从哪里来的呢 ?,答:没有地方来,子进程只能与其父进程执行一样的代码,我们所谓的:父进程和子进程共享且都会执行Linux操作系统所提供的系统调用接口 fork 调用处之前和之后的所有的代码以及该系统调用接口 fork 函数体内部的所有的代码,在此,本质上,子进程共享并执行 Linux 操作系统所提供的系统调用接口 fork 调用处之前和之后的所有的代码以及该系统调用接口 fork 函数体内部的所有的代码都是属于其父进程的代码,注意:父进程与子进程两者的数据(全局变量,静态变量等等数据)要各自独立开来,因为进程具有独立性,父子进程的数据必须是独立分开的,在后期讲解写时拷贝时再进行具体阐述,虽然父进程和子进程共享且都会执行Linux操作系统所提供的系统调用接口 fork 调用处之前和之后的所有代码以及该系统调用接口 fork 函数体内部的所有的代码,但是常规情况下,可以通过父进程和子进程各自的 id 变量中的值不同,在调用 Linux 操作系统所提供的系统调用接口 fork 之后,可以通过父进程和子进程中各自不同的 id 变量中的值进行判断,让父进程和子进程分别执行不同的代码块、
调用一个函数,当在这个函数的函数体中准备 return 时,此时该函数的主题,核心功能已经完成了,此处的 return ,并不是核心逻辑的一部分,这就意味着,当在 Linux 操作系统所提供的系统调用接口 fork 的函数体中,在执行 return 代码(语句)之前,其当前进程的子进程就已经被创建(启动)好了、
如何理解进程被运行?,我们知道,进程等于加载到内存中的可执行程序(代码及数据)加上该进程对应的内核数据结构( 该进程对应的描述该进程所使用的 struct 结构体(task_struct) ),但是并不代表描述某一个进程所使用的 struct 结构体只能在一个双链表(或其它高效的数据结构,但此处主要是指双链表)中,也可以同时放在另外一个双链表(或其它高效的数据结构,但此处主要是指双链表)中,其次,在操作系统内部存在一个我们称为调度器的代码模块、
在 Linux 内核中的每一个 CPU 中,都会存在一个叫做运行队列( runqueue )的东西,运行队列中所放的都是进程,所谓的调度器调度,就是让该运行队列中的每一个进程根据他们的优先级(使用队列就已经明确了优先级的问题)去被 CPU 运行,当某一个进程被调度,也就是被 CPU 运行时,本质上就是让 CPU 找到该进程对应的可执行程序(代码和数据),通过找到的代码去访问它的数据,这样就是运行了该进程,还要注意,我们所谓的创建(启动)某一个进程的子进程,该子进程还需要被 CPU 运行,还需要把该子进程放到运行队列中,以此供 CPU去调度,该子进程的可执行程序(代码和数据,此处所谓的数据是该子进程独立的数据,而此处所谓的代码指的就是该子进程的父进程的代码),由上述可知,在 Linux 操作系统所提供的系统调用接口 fork 的函数体中,当在执行 return 代码(语句)之前,其当前进程的子进程就已经被创建(启动)好了,即:在 Linux 操作系统所提供的系统调用接口 fork 的函数体中,在执行 return 代码(语句)之前,就已经存在了父进程和子进程,并且此时,父进程和子进程都已经放在了运行队列中,父进程和子进程都有可能随时被 CPU 调度,当两者都被 CPU 调度时,父进程和子进程共享且都会执行 Linux 操作系统所提供的系统调用接口 fork 调用处之前和之后的所有代码以及该系统调用接口 fork 函数体内部的所有的代码,所以此处就都会执行 Linux 操作系统所提供的系统调用接口 fork 的函数体中的 return代码(程序),因此,在 Linux 操作系统所提供的系统调用接口 fork 的函数体中进行两次返回操作,且有对应的两个返回值、
拓展:
我们在写 C 代码时所使用的变量,有可能并不是存在于内存中,实际上,这一个变量名最后会对应到不同的存储空间中,在讲解进程地址空间时再进行具体的阐述、