【Linux系统编程】进程状态

简介: 【Linux系统编程】进程状态

介绍


       进程的状态指的是进程在执行过程中所处的状态。进程的状态随着进程的执行和外界条件的变化而转换。我们可用 kill 命令来进程控制进程的状态。


       kill中的 kill -l 指令用于查看系统中定义的所有信号及其对应的编号。这些信号可以用于 kill 命令来向进程发送特定的信号控制其状态。例如,kill - 9 命令会向进程发送 SIGKILL 信号,强制终止进程,kill -19 命令会向进程发送 SIGSTOP 信号,使进程进入暂停状态,如同 Ctrl+Z 组合键的效果,kill -18 命令用于向进程发送 SIGCONT 信号,使进程从暂停状态恢复执行,如同 Ctrl+C 组合键的效果。


系统下的进程主流状态


       进程在系统中主流的四个主要状态:运行状态、排队状态、阻塞状态、挂起状态。


运行状态


       首先,要说明,系统内部的所有进程不是一次性执行完毕的,而是在内部排队等待某种资源。


       进程只要在运行队列里或正在被CUP正在执行时,此进程就处于运行状态。部分教材中可能会说明有创建状态、就绪状态、阻塞状态等,这几种状态其实都是跟进程放入运行队列有关。


排队状态


       由于大部分计算机中只有一个CUP,而一个CUP一次只能运行一个进程队列,所以在Linux系统内核中,所有进入状态的进程必须依次“ 排队 ”等待,这里的“ 排队 ”并不是进程自己在“ 排队 ”等待,而是进程的 tast_struct 结构体在进行“ 排队”等待被CUP执行。


       其实不光是等待CPU执行时需要排队,在进程等待某种资源时,也会处于排队状态。如外设等。这里的排队等待,不像一般数据结构中的排队等待,而是将 task_struct 结构体嵌入到运行队列中,系统通过地址偏移量来进行访问里面的属性数据。具体实现如下:


3fc75cf5b2114e7bad0a493eb8b8f8ea.png


       总的来说,进程的排队状态是指进程在等待被执行或等待获取资源时所处的一种状态。在排队状态下,进程会被放入相应的队列中,等待其前面的进程释放资源或完成其任务,当多个进程同时请求系统资源时,操作系统会根据一定的调度算法将这些进程按照一定的顺序排列,以便按照一定的优先级逐个分配资源。


阻塞状态


       阻塞状态是进程的执行过程中一种暂停状态,此时进程放弃处理机而处于暂停状态。当进程处于阻塞状态时会排成一个队列,形成这种情况通常是因为进程在等待某个事件的发生。如,当我们的进程在进行等待软硬件资源的时候,资源如果没有就绪,我们的进程task_struct 只能将自己设置为阻塞状态,并将自己的pcb连入等待的资源提供的等待队列。


挂起状态


       进程的挂起状态是指一个进程由于某些原因暂时不能执行,而被系统挂起来,等待以后执行。在这种状态下,进程不会占用内存空间,也不会被调度执行,进程只是被存储在磁盘上。这种状态通常发生在系统资源不足或者进程等待某些事件时发生。当条件允许时,被挂起的进程就会被操作系统再次调回内存,重新进入等待被执行的状态,即就绪态。


前台进程与后台进程  


       前台进程和后台进程是操作系统中的两种进程类型,它们在运行状态和行为上存在显著差异。一般情况下,进程中的可执行程序直接运行是前台进程,当在执行可执行程序时,在后面加上“ & ”符号,就变成了后台进程。前台进程和后台进程在进程状态符观察出。当查看进程状态时,若状态符后面有“ + ”号,此进程表示前台进程,若状态符后面没有“ + ”号,此进程表示后台进程。    


       通常情况下,前台进程可以直接使用键盘上的 Ctrl+C 来终止,但后台进程则需要使用特定的命令,如“ kill -9 [PID] ”来终止。因此,当我们设为后台进程时,用户必须要获取该进程的PID。


Linux内核源代码的进程状态


       在了解进程状态时,首先要明白系统内部定义的进程状态。在Linux内核中定义状态的源代码如下:


/*
* 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运行状态:表示进程正在处于系统的运行状态,与上面的运行状态效果一样,并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。


       S睡眠状态:进程在等待某件事件完成而进入睡眠。这种睡眠状态如同阻塞状态,有时候也叫做可中断睡眠,可直接用键盘进行中断。


       D磁盘休眠状态:这种状态有时候也叫不可中断睡眠状态,它用于资源管理。当进程的PCB指针放入磁盘结构体的队列中时,如果内存紧张,操作系统可能需要终止一些后台进程来缓解内存压力。但是,如果正在写入磁盘的数据很重要,直接终止可能会导致不良后果。此时将进程置于D状态可以确保即使在内存紧张的情况下,操作系统也不会终止它,直到IO操作完成。


       T停止状态:表示进程被暂定,如同 kill -19 命令停止运行进程。此状态也可理解为阻塞状态的分支。


       t停止状态:表示进程处于跟踪状态而暂定,通常用于调试目的。


注意:状态T和状态t都是表示进程被停止,其中,状态T停止是常规控制停止,而状态t停止是因为深入跟踪导致进程停止,通常用于调试。


       X死亡状态:此状态表示进程已经结束,并且可以被回收的状态。当一个进程完全结束执行,并且系统已经回收了其资源时,该进程就会进入X状态,因此,这个状态只是一个返回状态,我们不会在任务列表里看到这个状态。


       Z僵尸状态:表示一个进程已经结束执行,但其父进程还没有读取它的退出状态信息。在这种情况下,该进程会以终止状态保持在进程表中,等待父进程读取其退出状态代码。


       当一个进程退出时,它会将退出信息保存在task_struct中,供父进程或操作系统读取。如果父进程在子进程退出后仍然存在,但没有读取子进程的退出状态信息,子进程就会进入Z状态。处于Z状态的进程不会占用CPU资源,但会占用进程表中的一个槽位和内存,直到其父进程读取了其退出状态信息并对其进行回收,因此,僵尸进程可能会造成内存资源的浪费,有一定的危害。以下代码的子进程就为僵尸进程。


#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
    pid_t id = fork();
    if (id == 0)  //子进程
    {
        int n = 5;
        while (n)
        {
            cout << "PID: " << getpid() << "   " << "PPID: " << getppid() << endl;
            sleep(1);
            n--;
        }
        exit(0);  //子进程退出
    }
    while (1)  //父进程运行
    {
        cout << "PID: " << getpid() << "   " << "PPID: " << getppid() << endl;
        sleep(1);
    }
    return 0;
}

孤儿进程


       孤儿进程是指一个进程的父进程已经终止,而该进程还在运行。


       由于孤儿进程原有的父进程已不存在,所以,孤儿进程通常由init进程(进程号为1)收养,并由init进程对它们完成状态收集工作。因此,孤儿进程并不会有什么危害。以下是孤儿进程的代码


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t id = fork();
    if (id < 0) 
    {
        perror("fork");
        return 1;
    }
    else if (id == 0)   //子进程
    {
        cout << "I am child, pid : " << getpid() << endl;
        sleep(5);
    }
    else  //父进程
    {
        cout << "I am child, pid : " << getpid() << endl;
        sleep(5);
        exit(0);
    }
    return 0;
}
目录
打赏
0
0
0
0
1
分享
相关文章
【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件
本文详细介绍了Linux中的进程IO与系统调用,包括 `open`、`write`、`read`和 `close`函数及其用法,解释了文件描述符(fd)的概念,并深入探讨了Linux中的“一切皆文件”思想。这种设计极大地简化了系统编程,使得处理不同类型的IO设备变得更加一致和简单。通过本文的学习,您应该能够更好地理解和应用Linux中的进程IO操作,提高系统编程的效率和能力。
53 34
|
8天前
|
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
38 17
|
8天前
|
Linux系统之whereis命令的基本使用
Linux系统之whereis命令的基本使用
50 23
Linux系统之whereis命令的基本使用
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
40 16
|
17天前
|
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
50 26
Linux系统查看操作系统版本信息、CPU信息、模块信息
在Linux系统中,常用命令可帮助用户查看操作系统版本、CPU信息和模块信息
111 23
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
137 2
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)
通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。
122 20
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
121 13
|
4月前
|
手把手教会你安装Linux系统
手把手教会你安装Linux系统
121 0

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等