Linux进程状态

Linux 进程状态:

进程状态RTASK_RUNNING
可中断状态STASK_INTERRUPTIBLE
不可中断睡眠状态DTASK_UNINTERRUPTIBLE
暂停状态TTASK_STOPPED
僵尸状态ZTASK_COMBIE
退出状态XTASK_DEAD

让我们来看一个示例图:

我们来实现一个僵尸状态

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

using namespace std;

// main函数启动,程序主进程
int main()
{

	int number = 100;

	// fork作用:创建新的子进程
	// 一次调用 ,两次返回
	pid_t pid = fork();

	if (pid == 0)
	{
		for (int x = 0; x < 5; x++)
		{
			cout << "子 getpid=" << getpid() << " x=" << x << endl;
			sleep(1);
			number++;
		}
	}
	else if (pid > 0)
	{
		for (int x = 0; x < 10; x++)
		{
			cout << "父 getpid=" << getpid() << " x=" << x << endl;
			sleep(1);
		}
	}


	return 0;
}

 这就是一个僵尸状态,这个状态的子进程比父进程逻辑结束更早,进程没有逻辑可执行,子进程僵尸状态会占着内存,并不会清空。

如果当父进程结束得比子进程早,子进程就会成为孤儿进程:孤儿进程会被 init 进程(在 Linux 系统中,进程 ID 为 1 的进程)或 systemd 进程收养,由它们来负责回收孤儿进程的资源。但后续逻辑出现了问题,则不会有后续处理

当然这两个我们都不希望它们出现。

我们先来学习一个wait函数(阻塞式函数)

功能概述

在多进程编程中,父进程创建子进程后,有时需要等待子进程执行完毕,获取子进程的退出状态,以确保资源的正确回收和程序逻辑的正确执行。wait 函数就提供了这样的机制,它可以让父进程暂停执行,直到它的某个子进程终止,然后获取该子进程的终止状态信息。

头文件

#include <sys/types.h>
#include <sys/wait.h>

函数原型

pid_t wait(int *status);

  • 参数status 是一个整型指针,用于存储子进程的退出状态信息。如果不需要获取子进程的退出状态,可以将其设置为 NULL
  • 返回值:如果调用成功,返回终止子进程的进程 ID;如果出错,返回 -1,并设置相应的错误码。

返回状态检测

宏定义描述
WIFEXITED(stat_val)子进程正常结束返回一个非0值
WEXITSTATUS(stat_val)如果WIFEXITED非0,返回子进程退出码
WIFSIGNALED(stat_val)子进程未捕获信号中止返回非0值
WTERMSIG(stat_val)如果WIFSIGNALED非0,返回信号代码
WIFSTOPPED(stat_val)如果子进程终止返回一个非0值
WSTOPSIG(stat_val)如果WIFSTOPPED非0,返回一个信号代码

我们对代码进行以下修改

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

using namespace std;

// main函数启动,程序主进程
int main()
{
	int number = 100;

	// fork作用:创建新的子进程
	// 一次调用 ,两次返回
	pid_t pid = fork();

	if (pid == 0)
	{
		for (int x = 0; x < 5; x++)
		{
			cout << "子 getpid=" << getpid() << " x=" << x << endl;
			sleep(1);
			number++;
		}

		exit(0);
	}
	else if (pid > 0)
	{
		for (int x = 0; x < 10; x++)
		{
			int status;
			wait(&status);

			cout << "父 getpid=" << getpid() << " x=" << x << endl;
			sleep(1);
		}
	}

	// 两个进程的公共代码(都会执行)
	cout << "getpid=" << getpid() << "over" << endl;

	return 0;
}

看结果我们发现,父进程一直等待孩子进程结束才开始执行 

处理方案: 

一、僵尸状态解决:

子进程在逻辑结束时将状态返还给父进程,就不会出现僵尸状态

例如以下代码,给子进程加入一个exit(2),给父进程加入一个wait(&status)函数

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

using namespace std;

// main函数启动,程序主进程
int main()
{
	/*pid_t pid = getpid();

	while (1)
	{
		cout << "I am a process with PID: " << pid << endl;
		sleep(1);
	}*/

	int number = 100;

	// fork作用:创建新的子进程
	// 一次调用 ,两次返回
	pid_t pid = fork();

	if (pid == 0)
	{
		for (int x = 0; x < 5; x++)
		{
			cout << "子 getpid=" << getpid() << " x=" << x << endl;
			sleep(1);
			number++;
		}

		exit(2);
	}
	else if (pid > 0)
	{
		for (int x = 0; x < 10; x++)
		{
			int status;
			wait(&status);

			if (WIFEXITED(status) != 0)
			{
				cout << "status=" << WEXITSTATUS(status) << endl;
			}

			cout << "父 getpid=" << getpid() << " x=" << x << endl;
			sleep(1);
		}
	}

	return 0;
}

运行结果:

   

    二、孤儿进程解决 :

    利用wait()这个函数阻塞特性,在父进程逻辑做完的最后来等待子进程结束,使父进程结束的比子进程晚。

    总结:

    一个基本框架

    pid=fork();
    if(pid==0)
    {
        ......
        exit(0);
    }
    else if(pid>0)
    {
        // wait在逻辑前还是后要根据业务需求设置
        wait();
        ......
        wait();
    }

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值