Linux的进程与线程

一、简介

  • 进程:在Linux中,进程指正在运行的程序的示例。每个进程都有一个唯一的标识符(PID),并且可以包含代码、数据和文件描述符等信息。

    • 进程是操作系统的基本单位,它们在系统中相互独立地运行,并通过操作系统调度器进行管理。
  • 线程:在Linux中,线程是一种轻量级的执行流,是cpu调度的基本单位,可以共享同一个进程的地址空间、文件描述和其他资源。

    • 线程是进程的一部分,它们共享相同的代码段和数据段,但拥有自己的栈空间。

二、进程的生命周期

  • 五个阶段:

    • 创建(Created):操作系统接收创建进程的请求,为新进程分配资源,包括内存、文件描述符、进程控制块(PCB)等。创建阶段结束时,进程处于就绪状态,等待被调度器调度。

    • 就绪(Ready):进程在就绪队列中等待被调度。此时,进程已具备运行所需的全部资源,只是等待CPU的分配。一旦调度器决定将CPU时间分配给该进程,进程就会从就绪状态转变为运行状态。

    • 运行(Running):进程获得CPU时间片并实际运行。这是进程执行其指令的阶段。一个进程在运行状态下会:

      • 正常执行完其时间片后,被调度器暂停,返回到就绪状态;

      • 发出I/O请求或其他阻塞操作,进入阻塞状态;

      • 被操作系统强制终止,进入终止状态。

    • 阻塞(Waiting):进程在等待某个事件(如I/O操作完成、资源可用等)时进入阻塞状态。在阻塞状态下,进程不占用CPU时间。等待事件发生后,进程会从阻塞状态转回就绪状态,等待再次被调度。

    • 终止(Termination):进程完成其任务或被操作系统强制终止后进入终止状态。在这个阶段,操作系统会释放进程占用的资源,并删除进程的PCB。进程终止后,不再存在于系统中。

  • 进程的生命周期是不断循环的,一个进程可能通过执行结束或其他方式终止,也可能重新创建新的进程。

  • 这样的循环使得操作系统能够同时处理和管理多个进程,实现多任务的并发执行。
    image

示例:

  • 创建:
./sum_program
  • 运行:
int sum = 0;
for (int i = 1; i <= 1000; ++i) {
    sum += i;
}
  • 阻塞:
FILE *file = fopen("config.txt", "r");
if (file != NULL) {
    // 读取文件内容
    fclose(file);
}
  • 终止:
printf("The sum is %d\n", sum);

总结:

  1. 创建:输入命令运行程序,操作系统创建进程。
  2. 就绪:进程被放入就绪队列,等待CPU时间。
  3. 运行:进程获得CPU时间并执行计算。
  4. 阻塞:进程等待I/O操作完成,暂时停止运行。
  5. 终止:程序完成任务,进程结束,操作系统回收资源。

三、进程状态

状态 描述
D(uninterruptible sleep) 进程处于无法中断的睡眠状态,通常是因为正在执行阻塞的I/O操作
R(running or runnable) 进程正在运行或者已经就绪等待运行,它在运行队列中等待获取CPU时间片
S(interruptible sleep) 进程正在等待某个事件完成,例如等待I/O操作或信号量
T(stopped by job control signal) 进程被作业控制信号(例如SIGSTOP)停止了,通常是由用户或调试器发出的停止信号
t(stopped by debugger during the tracing) 进程被调试器在追踪期间停止了
W(paging) 在早期的Linux内核中,表示进程正在进行页面交换操作(在2.6.XX内核中已经不再使用)
X(dead) 表示进程已经终止,这个状态通常不应该被看到
Z(defunct/“zombie”) 表示进程已经终止,但是其父进程尚未回收相关资源,隐藏变成了僵尸进程
![image 642x287](upload://4v7Eq9wY3GvEd7sksBO17xe7N1u.png)

四、常用的进程管理命令

命令 说明
ps 进程列表快照
top 交互式进程观测
kill 结束进程
fg 进程切换到前台
bg 进程切换到后台
ctrl+z 挂起进程

4.1 ps命令

  • unix风格参数:ps -ef

  • bds风格参数:ps aux

  • gnu风格参数:ps -o pid,pidlist


4.2 top命令

  • 通过top命令,可以实时地查看系统各项性能指标、进程状态和资源占用情况,以便更好地了解和监控系统的运行状态。

  • 在top命令下,可以进行交互式操作,如切换排序方式、改变刷新间隔、显示不同的统计信息、发送信号给进程等。

    • P键:以CPU使用率进行排序;
    • M键:以内存使用量进行排序;
    • T键:按运行时间进行排序;
    • N键:按PID进行排序;
    • i键:切换显示所有进程和只显示活动进程;
    • d键:更改刷新时间间隔;
    • k键:杀死一个进程;
    • u键:显示特定用户的进程;
    • h键:显示帮助信息;
    • q键:退出命令。

4.3 kill命令

  • 结束进程,可以加上进程ID以杀掉指定进程。
    • kill PID xxx

4.4 jobs命令

  • jobs是一个shell内建命令,用于列出当前终端会话中正在运行或停止的进程。它会显示进程的ID和状态等。

4.5 fg命令

  • fg是一个shell内建命令,用于将一个停止的进程转移到前台运行。通过指定进程ID,fg命令将选择指定的进程并切换到前台运行。

4.6 ctrl+z命令

  • ctrl+z用于将当前正在运行的前台进程暂停,该进程会被挂起并放在后台运行。

4.7 bg命令

  • bg是一个shell内建命令,用于将一个已被暂停的进程转到后台继续运行。通过指定进程ID,bg命令将选择指定的进程,并将其放到后台继续执行。

五、I/O操作详解

  • I/O操作是指输入/输出操作(Input/Output Operation),它是计算机系统中与外部设备或其他系统之间进行数据交换的过程。

  • I/O操作是计算机与外界交互的基本方式,包括从输入设备获取数据(输入)和将数据发送到输出设备(输出)。

5.1 I/O操作的分类

1. 输入操作

输入操作指的是将外部数据输入到计算机系统中。常见的输入设备包括键盘、鼠标、扫描仪、麦克风等。例如,在键盘上输入文字时,这些文字被传输到计算机中,这就是一次输入操作。

2. 输出操作

输出操作指的是将计算机中的数据输出到外部设备。常见的输出设备包括显示器、打印机、扬声器等。例如,在屏幕上看到显示的图像或文字时,这就是一次输出操作。

5.2 I/O设备的种类

1. 块设备(Block Devices)

块设备可以一次读取或写入固定大小的数据块。硬盘、光盘和闪存都是典型的块设备。这些设备通常用于存储大量数据,并允许随机访问。

2. 字符设备(Character Devices)

字符设备一次处理一个字符或字节的数据。键盘、鼠标和串行端口都是字符设备。这些设备通常用于处理较小的数据流,并允许顺序访问。

5.3 I/O操作的实现方式

1. 同步I/O

在同步I/O操作中,I/O操作需要等待数据传输完成,才能继续进行后续的处理。这意味着在I/O操作完成之前,CPU会一直处于等待状态。这种方式可能会导致CPU资源的浪费,因为CPU在等待过程中无法执行其他任务。

2. 异步I/O

在异步I/O操作中,I/O操作在后台进行,CPU可以继续执行其他任务而不必等待数据传输完成。异步I/O可以提高系统的效率和响应速度,因为它允许并行处理多个任务。

3. 中断驱动I/O

中断驱动I/O是通过硬件中断来实现的。当I/O设备准备好数据时,会发送一个中断信号给CPU,通知CPU进行处理。这样,CPU可以在等待I/O操作的同时处理其他任务,而不会浪费时间。

4. 直接内存访问(DMA)

DMA是一种特殊的I/O技术,它允许I/O设备直接与内存进行数据交换,而无需经过CPU。这可以大大提高数据传输的效率,因为数据不需要通过CPU的控制。

5.4 I/O操作的示例

文件读写

打开一个文件并读取或写入数据时,就是在进行I/O操作。比如在C语言中,使用 fopen 打开文件,使用 freadfwrite 进行数据读写。

FILE *file = fopen("example.txt", "r");
char buffer[100];
fread(buffer, sizeof(char), 100, file);
fclose(file);

网络通信

网络通信也是一种常见的I/O操作。比如在网络编程中,使用 sendrecv 函数发送和接收数据包。

int sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
send(sock, "Hello", 5, 0);
recv(sock, buffer, 100, 0);
close(sock);