背景---创建子进程

进程状态_前台进程

进程的启动路径==当前工作路径==创建新文件/子进程 的默认路径

修改当前进程的工作目录 == 修改创建新文件/子进程 的默认路径wLA7Pwi.Ec3:zFm

#include <stdio.h>//必备头文件
#include <sys/types.h>//getpid
#include <unistd.h>//sleep, chdir, getpid需要

int main()
{
    chdir("/home/whb/111");//修改当前进程的工作目录

    FILE *fp = fopen("log.txt", "w");//打开文件
    (void)fp; // ignor warning 忽略警告(创建一个指针没使用时, 会报警告)
    fclose(fp);//关闭文件

    while(1)
    {
        printf("I am a process, pid: %d\n", getpid());
        sleep(1);
    }

    return 0;
}


1. 进程状态

1.1. 直接谈论Linux的进程状态

1.1.1. 一个进程中的状态属性(修改等)举例

进程状态_#include_02

1.1.2. 进程的状态 (属性值本身是个宏)

static const char * const task_state_array[] = {
        "R (running)", /* 0 */   		//在CPU运行/队列
        "S (sleeping)", /* 1 */			//浅休眠
        "D (disk sleep)", /* 2 */		//深休眠(磁盘休眠)
        "T (stopped)", /* 4 */			//暂停
        "t (tracing stop)", /* 8 */		//暂停
        "X (dead)", /* 16 */			//终止/释放
        "Z (zombie)", /* 32 */			//僵尸
    };


1.1.3. S+ 和 S的区别, +说明在后台, 不带+说明在前台

在Linux中,可以将进程分为前台进程和后台进程,它们的区别在于与终端的交互方式和执行状态。

前台进程:会有+

前台进程是当前正在与用户交互的进程,它会占用终端的输入和输出。

当用户在终端启动一个程序时,该程序通常成为前台进程,用户可以看到程序的输出,并且可以与程序进行交互。

前台进程会阻塞终端,直到该进程执行完毕或者暂停。

用户可以通过按下Ctrl + C来中断前台进程的执行。


后台进程:没有+

后台进程是在后台执行的进程,不会占用终端的输入和输出。

用户可以在命令行中在执行命令后面加上&符号,将进程放入后台执行。

后台进程不会阻塞终端,用户可以继续输入其他命令。

用户可以使用命令bg将一个前台进程转为后台进程,或者使用命令jobs查看当前所有的作业(包括前台和后台)。

使用kill 进程ID命令关闭对应的后台进程,比如kill 1234

1.1.4. 进程状态R, S的验证

vim中底行模式, 后者替换前者, :%s/原名称/替换后的名称

testStatus:testStatus.c
	gcc -o $@ $^ -g
.PHONY:clean  #.PHONY伪目标让clean总是被执行(因为如果是生产文件相关的命令, 源文件没有被再次修改时, 是不允许重复生成的)
clean:
	rm -f testStatus

/**************************************************************/

验证

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

int main()
{
    while(1)
    {
        printf("I am a process, pid: %d\n", getpid());
    }
    return 0;
}
while :; do ps ajx | head -1 && ps ajx | grep testStatus | grep -v grep; sleep 1; done  //死循环, 每轮执行后暂停1秒;    //ps ajx显示当前系统中的进程; -v是反向过滤

进程状态_#include_03

因为cpu速度非常快, 相对的显示器就显得很慢, CPU运行完一行printf代码, 把需要显示的内容先传输到内存, 在传给显示器; 假设CPU运行一次printf只用1纳秒, 但后面传给内存, 显示器需要100纳秒, 那么进程被cpu执行了1次printf后, 把结果传给内存, 再使用显示器(正在打印第一次printf的内容)资源几十纳秒, 在显示器显示一次结果期间, cpu可能已经执行了几十次, 传给内存缓冲区几十个结果, 都在等待显示器资源就绪. 所以进程的状态大部分都是S; 被CPU运行的过程叫执行过程R, 等待显示器资源得过程叫休眠(S)(不运行)

因为CPU与显示器的速度差距太大, 所以显得进程总是在等待显示器资源


R 是运行状态, 它表明进程要么是在运行中, 要么在运行队列里

S 是休眠/等待状态, 等待其它(CPU外)资源就绪 / 等待特定事件的完成(这里的睡眠有时候也叫做可中断睡眠(可以被ctrl+c 或 kill 终断)(interruptible sleep)

1.1.5. 状态T/t(追踪暂停)

1.1.5.1. kill指令—向进程发送信号, kill -l 进程的信号(都是宏)

进程状态_#include_04

9 SIGKILL是杀掉进程, 19 SIGSTOP是暂停进程, 18 SIGCONT继续进程, signal信号

调试时断点停止, 也是暂停, 等待进一步被唤醒


在Linux系统中,当一个进程接收到SIGSTOP信号时,它会被暂停(停止)执行,进入停止状态。在这种状态下,进程的执行被暂时挂起,不会继续执行,也不会被调度到CPU上运行。

停止状态下的进程不会消耗CPU资源,也不会响应任何信号,直到接收到SIGCONT信号后才会继续执行。停止状态的进程可以通过ps/pgrep命令或者类似的工具查看,通常会显示为T状态。

要将一个进程从停止状态恢复到运行状态,可以向该进程发送SIGCONT信号。这样进程就会从停止状态恢复到运行状态,继续执行kill指令—向进程发送信号

//在Linux系统中,kill指令用于向进程发送信号。通过kill指令,可以向指定的进程发送不同的信号,从而影响进程的行为。常用的kill指令格式如下:
kill [options] <PID>  //选项前最好加-, 否则OS可能会识别错误(kill 19识别成kill -9)

其中,<PID>是要发送信号的进程的进程ID(Process ID)。可以使用ps指令或者pgrep指令来查找进程的进程ID。

  • 9:发送SIGKILL信号,强制终止进程。
  • 15(或不加选项):发送SIGTERM信号,请求进程正常终止。

kill -l是用来列出系统支持的信号列表的命令

  • 19 SIGSTOP(编号为19):发送SIGSTOP信号会使进程停止执行,进程将被挂起,直到接收到SIGCONT信号继续执行。SIGSTOP信号不能被捕获、忽略或阻塞,是一种强制停止进程的信号。
  • 18 SIGCONT(编号为18):发送SIGCONT信号会使之前被停止的进程继续执行。这个信号用于恢复被SIGSTOP或者类似信号暂停的进程的执行。


1.1.6. 磁盘睡眠D(Linux特有)

磁盘休眠状态

也是阻塞状态。D磁盘休眠状态(Disk sleep)是Linux系统中的一种进程状态,有时也称为不可中断睡眠状态(uninterruptible sleep)。进程进入这种状态通常是因为正在等待某些IO操作的完成,比如磁盘读写操作,网络请求等。在D状态下的进程是无法被中断或者唤醒的,直到IO操作完成为止。


  1. 问题:

当系统内存压力非常大时,操作系统有权利根据一定的策略选择杀死一些进程以释放内存空间,从而维持系统的稳定性和可用性。这种行为通常称为"内存压力控制"或"内存压缩",它是Linux内核中的一个重要特性之一。

有些进程正在等待1GB数据写入磁盘是否成功的返回信息, 但OS看他闲, 就直接把他释放了, 等到磁盘写入成功/失败后, 想返回信息, 发现进程没了, 磁盘只能继续给别的进程工作; 这1GB数据就全丢了, 没人知道它在哪, 是否存在了,

  1. 解决:

引入D状态, 处于D状态的进程不可被中断 / kill


  1. 消除D状态的方法: 进程自己醒, 关机/断电

进程状态_#include_05