【Linux学习之系统编程】Linux进程的概念

进程是什么

进程是操作系统对一个正在运行的程序的一种抽象,是计算机科学中最重要和最成功的的概念之一。

进程是操作系统理论的核心与基础,操作系统中的许多概念都和进程有关

进程的定义有很多,这里只列举几种:

·进程是一个独立的可调度的活动

·进程是一个抽象实体,当它执行某个任务的时候,要分配和释放各种资源

·进程是可以并行执行的计算单位

·进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动

·进程是一个执行实例,是一个正在执行的程序

进程是一个程序的一次执行的过程,同时也是资源分配的最小

进程和程序的区别

程序是静态的,它是一些保存在磁盘上的指令的有序集合

进程是动态的,它是程序执行的过程,包括了创建、调度和消亡的全过程

进程的组成

进程由三部分组成,进程控制块(PCB)、代码段和数据段

进程控制块(PCB)

进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合,Linux操作系统下的PCB是task_struct,task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

进程控制块里面都有这些内容:

·标识号

每个进程都有一个标识号(PID)和一个父进程的标识号(PPID),PID唯一标识一个进程,另外一个进程还有自己的用户(UID)和组标识号(GID),系统通过这两个标识号判断进程对文件的访问权限

·状态信息

一个Linux下的进程可以有这样几种状态:运行状态,睡眠状态,停止状态,磁盘休眠状态,僵死状态。状态信息还包括任务状态,退出代码,退出信号等。

·调度信息

调度器根据这些信息判定系统中哪个进程的优先级高,需要立即执行

·时间和定时器信息

系统在这些字段中保存进程的建立时间,以及在其生命周期所花费的CPU的时间。Linux也支持和进程相关的计时器,应用程序可以通过系统调用建立定时器,当定时器到期,操作系统会向该进程发送sigarlrm信号

·内存指针

包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针,

·上下文数据

进程的上下文用来保存进程相关的系统状态的字段,当调度程序将某个进程从运行状态切换到暂停状态时,会在上下文中保存当前的进程运行环境,包括CPU所有寄存器的值,进程的状态以及堆栈信息;当调度程序再次选择该程序运行时,则会从进程上下文信息恢复进程的运行环境

·文件系统信息

这类字段记录进程所打开的文件描述符信息,另外还包含指向虚拟文件系统的两个索引节点的指针,这两个索引节点分别是进程的主目录以及进程的当前目录。索引节点中有一个引用计数器,当有新的进程指向某个索引节点时,该索引节点的引用计数器就会增加。未被引用的索引节点的引用计数为0,因此当包含在某个目录中的文件运行时就无法删除这一个目录,因为这一个目录的引用计数大于0

·进程与其他进程之间的关系信息

在Linux中,除了根进程之外,任何一个进程都具有父进程,也有可能有兄弟进程或子进程。所以每个的PCB中包含了进程的父进程指针、与该进程具有同样父进程的兄弟进程指针以及进程的子进程指针。Linux还用一个双向链表记录系统中的所有进程,这个双向链表的根就是Init进程。

在Linux下查看进程

进程的信息可以通过/proc文件来查看,如图


我们写一段c代码:

然后用gcc编译

然后运行

再开一个窗口查看test进程,使用的指令为 ps aux | grep test

通过系统调用获取进程标识符

在Linux中获得当前进程的PID和PPID的系统调用函数为getpid()和getppid()

#include <stdio.h>                                                                                                                
#include <unistd.h>                                                                                                               
#include <sys/types.h>                                                                                                            

int main() {
	printf("pid = %d\n", getpid());
	printf("ppid = %d\n", getppid());
	return  0;
}

程序运行结果如下:

创建进程:fork函数

fork函数和c语言中以前的函数不同,它有两个返回值,fork函数成功调用之后给当前进程创建一个子进程,所以有了两个进程,fork函数在父进程中返回子进程的ID,在子进程中返回0

#include <stdio.h>                                                                                                                  
#include <unistd.h>                                                                                                                 
#include <sys/types.h>                                                                                                              

int main() {                                                                                               
	int ret = fork();
	printf("pid = %d, ret = %d\n", getpid(), ret);
	sleep(1);
	return  0;
}

代码运行结果如下:

fork函数调用后有一个父进程和子进程,这个父子进程代码共享,数据各开辟空间(采用写时拷贝)

fork函数通常要用ifelse对返回值进行判断,代码如下:

#include <stdio.h>                                                                                                                
#include <sys/types.h>                                                                                                            
#include <unistd.h>                                                                                                               

int main() {
	int ret = fork();
	if (ret < 0) {
		perror("fork");
		return 1;
	}
	else if (ret == 0) {
		printf("child: %d, ret = %d\n", getpid(), ret);
	}
	else {
		printf("father: %d, ret = %d\n", getppid(), ret);
	}
	return 0;
}

返回值ret大于0表示当前进程是父进程,返回值小于0表示当前进程是子进程

对fork函数的总结:

·fork失败的原因是父进程拥有的子进程数目超过了规定的限制

·操作系统把父进程的内存地址完全复制到子进程

·子进程继承了父进程的用户ID,组ID,当前目录,根目录,打开的文件,创建文件使用的屏蔽字,信号屏蔽,上下环境,共享的存储段,资源限制

  进程状态

进程是程序的执行过程,根据它的声明周期可以划分为5种状态(前三种为基本状态)

R运行状态(running),它并不意味着程序一定在运行中,它表明程序要么在运行中要么在运行队列里就绪

S睡眠状态(sleeping),它表示进程正在等待事件完成,这里的睡眠是可中断睡眠

D磁盘休眠状态(Disk sleep),有时候也叫做不可中断睡眠,在这个状态的进程通常会等待IO的结束

T停止状态(stopped),可以通过发送SIGSTOP信号给进程来停止进程,这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行,该状态主要用于调试

X死亡状态(dead),这个状态只是一个返回状态

还有一种状态:僵死状态(终止状态),进程已终止,但是task_struct结构仍然在内存中 ,处于这种状态的进程其实是一个死进程

进程的各种基本状态及其转换:

这个图不好画所以我是从网上找来的~~意思到了就行了

接下来模拟详细的介绍一下僵尸进程和孤儿进程

僵尸进程

僵尸进程是一个比较特殊的状态,一个进程在其终止的时候还保留一些信息,例如进程的ID号、进程的退出状态,进程运行的CPU时间等,因此进程终止时回收所有内核分配给它的内存,关闭它打开的文件等等,但是还会留有一些信息以供父进程使用,父进程可以使用wait/waitpid等系统调用来做一些收尾工作。

所以一个僵尸进程就是,当父进程调用fork函数创建一个子进程后,子进程运行到终止然后直接从内存中移出,但是进程描述符仍然在内存中,子进程的状态编程了EXIT_ZOMBIE,并且向发送SIGCHLD信号,父进程应该调用wait()系统调用来获取子进程的退出状态以及他的信息,当wait调用之后,僵尸进程就完全从进程中移除了。但是如果父进程没有调用wait等系统调用来收集僵尸进程,那么这个进程就会一直存在于内存中。

接下来我们模拟实现僵尸进程,代码如下:

如上代码,在pid等于0时进程为子进程,在子进程中我们直接退出,但是在父进程中并没有调用wait等系统调用,运行如下:

再刑一个窗口查看,我们发现blog1这个进程的状态是Z状态


我们等父进程也结束之后,再查看:

发现已经没有刚才的僵尸进程了,为什么呢?

因为父进程退出之后,所有的子进程都过继给init进程,init进程称为这个僵尸进程的新进程,而init进程会周期性的调用wait系统调用来清理它的子进程中的僵尸进程,所以父进程消失后僵尸进程也消失了。

僵尸进程的危害

僵尸进程如果不被父进程读取,就会一直维持下去,如果僵尸进程过多就会造成内存资源的浪费,而且还会造成内存泄露,最关键的是如果子进程不结束,其进程号就会一直被占用,如果产生大量僵尸进程,就会因为没有可用的进程号导致系统不能产生新的进程

孤儿进程

前面我们了解了僵尸进程,僵尸进程是父进程不读取子进程的返回信息导致子进程处于Z状态

孤儿进程是父进程提前退出,导致子进程退出之后没有父进程接受它返回的信息,这样的子进程称为孤儿进程

孤儿进程会被1号init进程领养

我们来实现一段代码:

    

运行之后我们可以看到

我们发现,一开始子进程的父进程pid是13031,在父进程退出之后它的父进程的pid就变为了1,而1号进程就是init进程,这就是孤儿进程

进程优先级

在操作系统中,CPU资源分配的先后顺序就是指进程的优先权,理所当然,优先权高的进程具有优先执行的权利

查看系统进程,如图:


如图,我们可以看到进程里面有这么几个主要选项:

UID:表示执行者身份

PID:当前进程的进程号

PPID:当前进程父进程的进程号

PRI:当前进程的优先级

NI:当前进程的nice值

PRI和NI的关系

PRI前面也说了,是进程的优先级,这个值越小进程的优先级越高

NI是进程的nice值,这个表示进程可被执行的优先级的修正数值

PRI值越小进程的优先级越高,加入nice值之后PRI值变为:PRI = PRI(old) + nice,当nice为负数的时候,该进程的PRI值就越低,进程的优先级就越高,所以调整进程的优先级在Linux下就是调整进程的nice值

nice的取值范围是-20——19,一共40个级别

注意:进程的nice值不是进程的优先级,但是进程的nice值会影响到进程的优先级变化,可以把nice值理解为进程优先级修正的修正数据

修改进程的优先级命令

方法一:启动前调整nice值

例如有一个test的可执行文件,然后在执行之前:

nice -n -5 ./test

方法二:调整已存在的进程的nice值

renice -5 -p pid

注意上面的pid是指要调整nice值得进程的pid

方法三:用top命令更改已存在进程的nice值

进入top以后按“r”—>输入进程PID—>输入nice值

进程的其它概念

竞争性:系统进程数目众多,而CPU资源只有少量甚至1个,所以进程之间是具有竞争属性的,为了高效的完成任务而合理的竞争相关资源便有了进程的优先级

独立性:多进程运行需要独享各种资源,多进程运行期间互不干扰

并行:多个进程在多个CPU下分别同时运行,这种情况叫做并发

并发:多个进程在同一个CPU下采用进程切换的方式,在一段时间之内多个进程同时推进,这种情况称之为并发


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值