目录
在了解进程概念前我们还得了解下冯诺依曼体系结构和操作系统的概念与定位。
1 冯诺依曼体系结构
我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系:
关于冯诺依曼,必须强调几点:
对冯诺依曼的理解,不能只停留在概念上,要深入到对软件数据流理解上,请解释,从你登录上qq开始和某位朋友聊天开始,数据的流动过程。
2 操作系统(Operator System)
概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
设计OS的目的
定位
总结
计算机管理硬件
系统调用和库函数概念
3 进程
有了上面对冯诺依曼体系结构和操作系统的理解,我们自然可以想到进程也是先描述,再组织。
3.1 基本概念
有些教材书上甚至是给出这样的定义的:进程就是程序加载到内存中。但是我觉得这种描述是狭隘的不够具体的,具体的我们下面会给出解释.
3.2 描述进程-PCB
task_struct是PCB 的一种:
我们将所有进程的属性用一个队列来维护,当我们想要加载程序时就将它的PCB链接到该运行队列中,这样就很好的维护了进程。
那现在我们再来回答什么是进程?
进程=当前程序的代码和数据+内核关于进程的相关数据结构
task_ struct内容分类:
3.2 组织进程
3.3 查看进程
我们在Linux环境中创建了一个profile.cpp的Cpp文件,然后编译运行生成了一个叫做profile的可执行文件,我们可以通过一下命令来查找进程:
ps ajx | head -1 && ps ajx | grep "查找进程的名字"
当我们运行profile后来查看:
不难发现我们查询到了profile进程的一些基本信息,如果我们想不加上下面那一行的信息可以将命令后面多加一些内容:
ps ajx | head -1 && ps ajx | grep "查找进程的名字" | grep -v grep
当然,文件名可加可不接双引号。
我们还可以在./proc中查询:
ls ./proc
3.4 通过系统调用获取进程标示符
我们向profile.cpp中写入以下代码:
1 #include<iostream>
2 #include<sys/types.h>
3 #include<unistd.h>
4 using namespace std;
5
6
7 int main()
8 {
9 while(1)
10 {
11 pid_t ret=getpid();
12 cout<<"hello"<<ret<<" "<<endl;
13 pid_t t=fork();
14 if(t==0)
15 {
16 while(1)
17 {
18 cout<<"我是一个子进程"<<" pid:"<<getpid()<<" ppid:"<<getppid()<<endl;
19 sleep(1);
20 }
21 }
22 else if(t>0)
23 {
24 while(1)
25 {
26 cout<<"我是一个父进程"<<" pid:"<<getpid()<<" ppid:"<<getppid()<<endl;
27 sleep(1);
28 }
29 }
30 }
31 return 0;
32 }
当我们查看进程时:
fork()后执行流会变成两个,是先执行父进程还是子进程是由调度器决定的,fork()后的代码共享,我们通常是用if else 来进行分流的。
当我们只读数据不写数据时,父子进程是共享代码的,而当有其中一个执行流尝试修改数据时OS就会在当前进程触发写时拷贝另外生成一份。
如何理解有两个返回值呢?
创建子进程本质上就是OS提供的一个函数,当函数内部进行return 时我们主体功能已经完成了。
3.5 进程状态
在了解进程状态前我们还得了解下什么是阻塞和挂起?
相信大家在看一些操作系统的书的时候就见过类似于这样的图片:
阻塞状态是一种等待某种资源就绪,而导致的一种不被推进的过程。这么说有点儿抽象,我们来举一个栗子:
当有大量进程存在时我们是不是要先描述,再组织,前面我们说过组织进程靠的是内核中以某种数据结构来维护进程的PCB。假设你在应用市场要下载一个软件,但是下到一半时网络突然中断了,那么操作系统会一直等到网络资源恢复后再去运行其他进程吗?显然是不会的,假如操作系统这样设计的话那么难道我们电脑上的其他程序就不运行了吗?就只等你一个?所以当网络资源中断时操作系统会将该进程从CPU的运行队列中拿走,放到对应硬件资源的等待队列中,等到网络资源恢复后再将该进程链接到CPU的运行队列中执行,而这种等待某种资源就绪而不被推进的一种状态就叫做阻塞状态。
而挂起又是什么意思呢?
由于机器的资源是有限的,在资源不足的情况下操作系统可以暂时将一些在内存中的进程淘汰出局,当条件允许的时候又会被操作系统给调回来,这个比较好理解就不在多做解释了。
看看Linux内核源代码怎么说
下面的状态在kernel源代码里定义:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
第一个R状态并不是表示进程在运行中,有可能是在运行队列里面。接下来给出大家一个程序大家猜猜这时一种什么状态?
1#include<iostream>
2 #include<unistd.h>
3 using namespace std;
4
5 int main()
6 {
7 while(1)
8 {
9 cout<<"我是一个进程 我的pid是:"<<getpid()<<endl;
10 }
11 return 0;
12 }
我相信第一次大家或许都会想:既然是死循环那么程序肯定在运行状态了,也就是R状态,事实真的是这样吗?我们一起来看看:
我们居然惊奇的发现,该进程居然处于S状态,这不合理吧?
那后面的+号是什么意思呢?
当我们注释掉代码里的打印字符时:
1 #include<iostream>
2 #include<unistd.h>
3 using namespace std;
4
5 int main()
6 {
7 while(1)
8 {
9 // cout<<"我是一个进程 我的pid是:"<<getpid()<<endl;
10 }
11 return 0;
12 }
再来看看:
我们会发现代码进程的状态已经变成了R.
同理,当我们往键盘中输入数据时几乎绝大多数都是S状态,只有刚输入数据那一瞬间才是R状态。
D状态是一种不可中断休眠状态,这时就算是强如操作系统都不能够干掉他,但是这种场景一般很少见,除非机器快宕机了。
T状态是一种停止状态,我们可以通过一个命令来改变当前的状态位T状态,大家可以查看有哪些kill命令:
kill -l
这时就会出现很多与kill相匹配的选项:
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
这里我们使用19号命令来暂停进程:
kill -19 进程的pid
那如何恢复呢?
可以用kill命令配带的18号选项:
kill -18 进程的pid
但是大家发现没有,这里的S状态是没有加+,也就是该进程是在后台运行的,不可以被ctrl+c终止
这时应该怎么处理呢?
我们可以试试kill带的9号选项:
kill -9 进程的pid
这时该进程已经被干掉了。
除了T状态还有一个t状态,这里的t表示的一种追踪暂停,类似于我们打断点运行到断点处:
我们可以打开Makefile加入断点信息,然后调试起来
不难发现此时的状态已经变成了t.
至于后面的X和Z状态将会放在下一节课来讲解,如果该文对你有帮助的话能不能3连支持一下博主呢?