【Linux】进程管理

一、程序与进程区别

1.程序:

存放在磁盘文件可执行文件(静态存在)

  • 特点
    • 静态性:程序是静态的,它只是一组指令的集合,在未被执行时,不会占用计算机的运行资源,也不会产生任何实际的操作。
    • 可执行性:程序经过编译或解释后,可以被计算机系统识别和执行,从而实现特定的功能。
    • 永久性:程序可以长期存储在存储设备中,只要存储介质不损坏,程序就可以一直存在,并在需要时被调用和执行。

2.进程:

运行起来的程序,占用内存空间(动态存在),每个进程都有一个唯一的数字标识符,进程id唯一,但限制时间为这一次的开机维持时间,id随机分配,

  • 特点
    • 动态性:进程是动态的,它在执行过程中会不断地改变自身的状态,如从就绪状态到运行状态,再到阻塞状态等。
    • 并发性:多个进程可以在同一时间内并发执行,操作系统会通过调度算法来分配 CPU 时间片,使得各个进程能够交替执行,从而实现多任务处理。
    • 独立性:每个进程都有自己独立的地址空间、内存空间、打开的文件等资源,不同进程之间的资源相互隔离,以保证进程的独立性和稳定性。
    • 生命周期性:进程有一个从创建到结束的生命周期,在这个过程中,它会经历各种状态的转换,最终完成任务并结束运行。

二、进程结构

        PCB 就像是进程的 “管理档案”,记录着进程的各种信息,而代码段、数据段和堆栈段则是进程运行时所用到的不同功能区域的内存空间。它们共同构成了 Linux 下的进程结构,彼此相互配合,使得进程能够正常运行。

提示:按ctrl+c可以退出运行程序

三、进程函数

返回值为pid_t只是在内核函数里面进行宏定义,为了便于区分,实际id返回还是int型

pid_t fork(void);

返回:子进程中为0,父进程中为子进程I D,出错为-1

#include <iostream>
#include <unistd.h>

using namespace std;

int main()
{
	int num = 0;
	//开辟新的进程,直接将完整整个函数拷贝(代码段),还拷贝了代码运行的状态,所以子进程从fork之后开始运行
	//数据段:还可以复制里面的数据
	int pid = fork();
	if (pid > 0)
	{
		while (1)
		{
			cout << "主进程id=" << getpid() << "  主进程的父进程id=" << getppid()<< "number= " << num++ << endl;
			sleep(1);
		}
	}
	else if(pid==0)
	{
		while (1)
		{
			cout << "子进程id=" << getpid() << "  子进程的父进程id=" << getppid() << "number= " << num++ << endl;
			sleep(1);
		}
	}
	return 0;
}

运行结果:

if与else都运行了,并且num的值在主进程与子进程中各自执行++,互不影响

四、孤儿进程、僵尸状态

进程结束:程序结束不再是main函数走完,而是所有的进程走完,才算结束,看不见窗口也不代表程序的结束(exit()或者retuern;)

孤儿进程:当主进程比子进程先结束时,子进程的getppid()函数返回父进程id为/sbin/upstart(系统进程)        

僵尸进程:子进程先于父进程结束,子进程本应该被释放,但不会将子进程释放,让子进程进入僵尸状态(Z+)

这两种情况都会让数据、逻辑出现问题,真实业务操作不会去做sleep,而是依靠cpu时间片轮转执行,解决方案:wait+exit让逻辑出现比较可控的操作

wait(&status);

//等待接收子进程结束状态码,父进程就能知道子进程是否已经结束
//阻塞式函数;逻辑中断

 //如果没有接收到状态码,就一直堵在这里,不执行后面代码

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;
int main()
{
	int pid = fork();
	if (pid > 0)
	{
			int status;
			for (int i = 0; i < 10; i++)
			{
				cout << "父进程i=" << i << endl;
				sleep(1);
			}
			//等待接收子进程结束状态码,父进程就能知道子进程是否已经结束
			//阻塞式函数;逻辑中断
			//如果没有接收到状态码,就一直堵在这里,不执行后面代码
			wait(&status);
			//waitpid(pid,&status,0);
			if (WIFEXITED(status))//返回真正自己定义的退出码
			{
				int x = WEXITSTATUS(status);
				cout << "子进程over退出码=" << x << endl;
				//父类处理子进程问题
				/*
					switch(x)
					{
					case 0:
						用户友好提示
						break;
					case 1:
						父类重新执行一次业务
						break;
					case 2:
						记录错误日志
						break;
					}
				*/
			}
	}
	else if(pid==0)//子进程
	{
		for (int i = 0; i < 25; i++)
		{
			cout << "子进程1号i=" << i << endl;
			sleep(1);
		}
		exit(1);
		//返回不同状态码让父进程处理不同逻辑
		/*
			if(业务成果)
			{
				exit(0);
			}
			else if(失败1)
			{
				exit(1);
			}
			else if(失败2)
			{
				exit(2);
			}
		*/
	}
	return 0;
}

但是wait无论有多少个子进程,只接收第一个最先结束子进程退出码

所以使用waitpid,等待特定最慢的进程结束(因为知道pid进程最慢)


waitpid(pid,&status,0);

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;
int main()
{
	int pid = fork();
	if (pid > 0)
	{
		int otherpid = fork();
		if (otherpid == 0)
		{
			for (int i = 0; i < 15; i++)
			{
				cout << "子进程2号i=" << i << endl;
				sleep(1);
			}
			exit(2);
		}
		else if(otherpid>0)
		{
		
			int status;
			for (int i = 0; i < 10; i++)
			{
				cout << "父进程i=" << i << endl;
				sleep(1);
			}
			waitpid(pid,&status,0);
			if (WIFEXITED(status))//返回真正自己定义的退出码
			{
				int x = WEXITSTATUS(status);
				cout << "子进程over退出码=" << x << endl;
			}
		}
	}
	else if(pid==0)//子进程
	{
		for (int i = 0; i < 25; i++)
		{
			cout << "子进程1号i=" << i << endl;
			sleep(1);
		}
		exit(1);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值