【OS】Process Management(3)

news2025/4/17 6:31:14

在这里插入图片描述

《计算机操作系统(第三版)》(汤小丹)学习笔记

文章目录

  • 5、进程通信(Inter-Process Communication)
    • 5.1、进程通信的类型
      • 5.1.1、共享存储器系统(Shared Memory System)
      • 5.1.2、消息传递系统(Message Passing System)
      • 5.1.3、管道通信系统(Pipe)
    • 5.2、消息传递通信的实现方法
    • 5.3、消息传递系统实现中的若干问题
    • 5.4、消息缓冲队列通信机制
  • 6、线程(Threads)
    • 6.1、线程的基本概念
    • 6.2、线程间的同步和通信
    • 6.3、线程的实现方式
    • 6.4、线程的实现


5、进程通信(Inter-Process Communication)

进程通信(IPC, Inter-Process Communication)是操作系统中实现不同进程间数据交换和信息传递的核心机制

信号量机制作为同步工具是卓有成效的,但作为通信工具,则不够理想,主要表现在下述两方面

  • 效率低
  • 通信对用户不透明

5.1、进程通信的类型

  • 共享存储器系统(Shared Memory System)
  • 消息传递系统(Message Passing System)
  • 管道通信系统(Pipe)

5.1.1、共享存储器系统(Shared Memory System)

共享存储器系统(Shared Memory System)是进程通信的一种高效方式,其核心思想是让多个进程直接访问同一块物理内存区域。

(1)基于共享数据结构的通信方式

原理:

  • 进程通过预定义的结构化数据对象(如链表、树、哈希表等)进行通信。这些数据结构在共享内存中创建,所有进程按约定规则读写特定字段。

特点:

  • 强结构化:数据按固定格式组织,便于类型检查和错误预防
  • 操作原子性:通常配合信号量实现关键操作的原子性(如插入/删除节点)
  • 低灵活性:需提前定义数据结构,扩展性较差

典型场景:

  • 实时系统监控(各进程更新统一的状态树)
  • 多进程协作计算(如分布式算法中的共享参数表)
  • 进程间传递复杂对象(如共享任务队列)

这种通信方式是低效的,只适用于传递相对少量的数据

(2)基于共享存储区的通信方式

原理:

  • 将共享内存划分为多个独立存储区域(如缓冲区、堆等),各进程通过协商好的地址范围进行读写。

特点:

  • 高度灵活:进程可自由管理自己的内存区域
  • 弱结构化:数据格式由进程自行定义,适合动态数据
  • 需显式同步:通常使用信号量或互斥锁保证数据一致性

典型场景:

  • 大数据量实时传输(如音视频流处理)
  • 动态内存分配(如多进程共享堆内存)
  • 进程间传递二进制数据块(如图像传输)

在这里插入图片描述
选择建议

  • 需要严格数据格式和类型安全时 → 选择共享数据结构
  • 处理二进制流或动态内存分配时 → 选择共享存储区
  • 高性能要求场景可结合两者:用共享数据结构管理元数据,用共享存储区传输实际数据

实际系统中常将两种方式结合使用,例如:用共享数据结构维护通信协议,用共享存储区传输原始数据,从而兼顾结构化和灵活性。

5.1.2、消息传递系统(Message Passing System)

进程通信中的消息传递系统(Message Passing System)是一种通过发送和接收结构化消息(message) 来实现进程间通信(IPC)的机制。与共享内存等直接访问内存的方式不同,消息传递系统强调通信的显式性和数据封装性,其设计核心思想可以概括为:“进程通过交换自包含的消息进行协作”。

计算机网络中 message 又称为报文

微内核与服务器之间的通信,无一例外地都采用了消息传递机制

一、核心组成要素

(1)消息(Message)

  • 结构化数据单元,通常包含:

    • 消息头:标识消息类型、发送者PID、优先级等元数据
    • 消息体:实际传输的数据(支持多种数据类型,如整型、字符串、结构体等)
  • 示例消息结构:

typedef struct {
    int type;          // 消息类型码
    pid_t sender_pid;  // 发送进程ID
    union {
        int int_data;
        char* str_data;
        struct complex_data* custom_data;
    } payload;         // 消息负载
} Message;

(2)消息队列(Message Queue)

  • 内核管理的先进先出(FIFO)缓冲区

  • 关键特性:

    • 异步通信:发送方无需等待接收方立即处理
    • 流量控制:队列满时阻塞发送方,空时阻塞接收方
    • 多消息类型支持:通过type字段实现消息分类

(3)通信端口(Port)

  • 进程用于接收消息的端点
  • 两种主要类型:
    • 临时端口:动态创建,通信结束后销毁
    • 永久端口:预先定义,支持长期通信

二、实现方式分类

(1)直接通信(Direct Communication)

进程通过显式指定接收方PID发送消息

优点:通信路径明确,适合点对点通信

缺点:耦合度高,接收方PID变化需同步修改

// 发送消息
send(target_pid, &message, sizeof(message), 0);

// 接收消息
recv(source_pid, &message, sizeof(message), 0);

(2)间接通信(Indirect Communication)

通过共享消息队列/邮箱进行通信

优点:解耦发送方和接收方,支持一对多/多对多通信

缺点:需要额外机制管理队列访问

// 创建消息队列
mqd_t mq = mq_open("/my_queue", O_CREAT | O_RDWR, 0666, NULL);

// 发送消息到队列
mq_send(mq, (const char*)&message, sizeof(message), 0);

// 从队列接收消息
mq_receive(mq, (char*)&message, sizeof(message), NULL);

三、优缺点
在这里插入图片描述

5.1.3、管道通信系统(Pipe)

进程通信中的管道(Pipe)是一种经典的进程间通信(IPC)机制,基于生产者-消费者模型,允许具有共同祖先的进程通过共享文件描述符进行单向数据传输。其设计哲学可概括为:“数据像水流一样在管道中流动,从一端进入,另一端流出”。

一、核心特性解析

(1)单向通信

  • 数据只能单向流动(从写端到读端)
  • 若需双向通信,需创建两个管道
  • 示例:
# 命令行管道示例(ls的输出作为grep的输入)
ls | grep ".txt"

(2)血缘关系限制

  • 匿名管道(pipe()创建)仅适用于父子进程或兄弟进程
  • 命名管道(FIFO,mkfifo()创建)允许无亲缘关系进程通信

(3)原子性保证

  • 单次write()操作的数据量≤PIPE_BUF时(通常4096字节),保证原子写入
  • 超过PIPE_BUF时可能分多次传输

(4)内核缓冲区

  • 数据暂存在内核内存区域
  • 读操作从缓冲区头部取数据
  • 写操作从缓冲区尾部追加数据

二、与消息队列的对比

在这里插入图片描述

5.2、消息传递通信的实现方法

消息传递通信是进程间通信(IPC)的重要范式,其核心思想是通过结构化消息在进程间传递信息。根据通信过程中是否直接指定接收方,可分为直接通信和间接通信两种方式。

(1)直接通信方式

实现原理

点对点消息传递

  • 发送进程需明确指定接收进程的标识符(如PID或端口号)
  • 操作系统内核负责将消息直接投递到目标进程
#include <mqueue.h>

// 创建/打开消息队列
mqd_t mq = mq_open("/myqueue", O_CREAT | O_RDWR, 0666, NULL);

// 发送消息(直接指定接收队列)
char buffer[1024];
mq_send(mq, buffer, sizeof(buffer), 0);

// 接收消息(从指定队列获取)
ssize_t bytes = mq_receive(mq, buffer, sizeof(buffer), NULL);

特点分析
在这里插入图片描述
典型应用场景

  • 实时系统:传感器数据采集与即时响应
  • 客户端-服务器模型:已知固定服务端地址
  • 任务调度系统:Worker 进程向 Manager 进程汇报状态

(2)间接通信方式

实现原理

通过共享数据结构通信

  • 消息存储在消息队列、Mailbox(邮箱、信箱)或端口等中介结构中
  • 发送方将消息存入队列,接收方从队列获取消息
#include <sys/msg.h>

// 创建/访问消息队列
int msgid = msgget(1234, 0666 | IPC_CREAT);

// 定义消息结构
struct msgbuf {
    long mtype;    // 消息类型
    char mtext[512];
};

// 发送消息(指定消息类型)
struct msgbuf msg = {1, "Hello"};
msgsnd(msgid, &msg, sizeof(msg)-sizeof(long), 0);

// 接收消息(按类型过滤)
msgrcv(msgid, &msg, sizeof(msg)-sizeof(long), 1, 0);

特点分析
在这里插入图片描述

典型应用场景

  • 分布式系统:微服务架构中的异步通信
  • 事件驱动系统:GUI框架中的事件分发
  • 批处理系统:任务队列中的作业调度

性能维度对比

在这里插入图片描述


信箱

在进程通信的信箱模型(Mailbox Model)中,信箱作为消息传递的中介,根据访问权限和使用方式可分为私用信箱、公用信箱和共享信箱。

私用信箱(Private Mailbox)

  • 所有权:由进程独占创建,仅允许创建者访问
  • 生命周期:随进程终止自动销毁

公用信箱(Public Mailbox)

  • 所有权:由操作系统创建,可供多个进程访问
  • 访问控制:通过权限位(如读/写/执行权限)管理

共享信箱(Shared Mailbox)

  • 所有权:由多个协作进程共同创建和维护
  • 同步机制:需显式处理并发访问(如信号量)

在这里插入图片描述


在利用信箱通信时,发送进程和接受进程之间存在以下四种关系

  • 一对一
  • 一对多(广播)
  • 对多一(client / server interaction)
  • 多对多(公用信箱)

5.3、消息传递系统实现中的若干问题

(1)通信链路(Communication Link)

在消息传递系统中,通信链路(Communication Link)是消息传输的通道,负责在发送方和接收方之间建立可靠的传输路径。其设计直接影响系统的性能、可靠性和扩展性

根据通信链路的链接方法,可以把通信链路分为

  • 点—点通信链路
  • 多点连接链路

根据通信方式的不同

  • 单向通信链路
  • 双向链路

根据容量的不同

  • 无容量通信链路(无缓冲区)
  • 有容量通信链路(有缓冲区)

(2)消息的格式(Message Format)

在消息传递系统中,消息格式(Message Format)是定义消息结构和内容的协议规范,直接影响系统的互操作性、序列化效率及扩展能力。

消息头(Header)
元数据字段:

  • 消息ID(唯一标识)
  • 源地址/目标地址(如进程ID、网络坐标)
  • 时间戳(用于排序/超时处理)
  • 消息类型(如请求/响应/事件)
  • 版本号(支持协议升级)

消息体(Payload)
数据表示方式:

  • 结构化数据(如JSON/XML)
  • 二进制数据(如Protocol Buffers)
  • 混合类型(如Thrift支持多语言映射)

定长消息格式 vs 变长消息格式

(3)进程同步方式

  • 发送进程阻塞,接收进程阻塞
  • 发送进程不阻塞,接收进程阻塞
  • 发送进程和接收进程均不阻塞

5.4、消息缓冲队列通信机制

(1)消息缓冲队列通信机制中的数据结构

1)消息缓冲区(Message Buffer)

type message buffer=record
	sender : 发送者进程标识符
	size:消息长度
	text:消息正文
	next:指向下一个消息缓冲区的指针
end

2)PCB中有关通信的数据项

  1. 消息队列标识符(mqid)
    作用:唯一标识进程关联的消息队列
    实现:通过系统调用msgget()获取
  2. 消息缓冲区地址(msg_buf)
    作用:指向进程接收/发送消息的缓冲区
    实现:通过系统调用msgrcv()/msgsnd()操作
  3. 消息类型掩码(msg_type)
    作用:过滤特定类型的消息
    实现:支持优先级或分类处理
  4. 消息长度限制(msg_max)
    作用:防止缓冲区溢出
    实现:由系统参数MSGMNB定义
  5. 消息队列状态(mq_state)
    作用:跟踪队列的可用性(如是否已满)
    实现:通过原子操作维护状态
type processcontrol blcok=record
	...
	mq:消息队列队首指针
	mutex:消息队列互斥信号量
	sm:消息队列资源信号量
	...
	end

(2)发送原语

在这里插入图片描述

procedure send(receiver, a)
	begin
		getbuf(a.size, i); 			根据 a.size 申请缓冲区
		i.sender:=a.sender;			将发送区 a 中的信息赋值到消息缓冲区 i 中
		i.size:=a.size;		
		i.text:=a.text;
		i.next:=0;
		getid(PCB set, receiver.j);	获得接收进程内部标识符
		wait(j.mutex);
		inser(j.mq,i);  			将消息缓冲区插入消息队列
		signal(j.mutex);
		signal(j.sm);
	end

(3)接收原语

procedure receive(b)
	begin
		j:=internal name;  		j为接收进程内部标识符 
		wait(j.sm);				
		wait(j.mutex)
		remove(j.mq,i);			将消息队列中第一个消息移出
		signal(j.mutex);
		b.sender:=i.sender;		将消息缓冲区 i 中的信息复制到接受区 b
		b.size:=i.size;
		b.text:=i.text;
	end

6、线程(Threads)

线程(Threads) 是进程中的一个执行单元,是CPU调度和分派的基本单位。

线程共享进程的资源(如内存、文件描述符等),但有独立的执行栈和程序计数器(PC)。

6.1、线程的基本概念

(1)线程的引入

在计算机程序设计中,进程是操作系统分配资源的基本单位,每个进程都有独立的内存空间和系统资源。然而,随着计算机性能的提升和用户对程序并发性需求的增加,传统基于进程的并发模型暴露出以下问题:

  • 资源开销大:每个进程需要独立的内存空间和资源(如文件描述符、网络连接等),导致系统资源浪费。

  • 切换成本高:进程切换需要保存和恢复整个进程的上下文(如寄存器、内存映射等),导致性能开销较大。

  • 通信复杂:进程间通信(IPC)需要借助操作系统提供的机制(如管道、消息队列、共享内存等),实现复杂且效率较低。

为了解决这些问题,线程被引入到操作系统中。

线程引入的目的

  • 降低资源开销
  • 提高并发性
  • 简化通信

(2)线程与进程的比较

进程:一个独立的工厂,拥有自己的仓库和生产线。

线程:工厂中的多个工人,共享仓库和生产线,但各自负责不同的任务。

线程具有许多传统进程所具有的特征,所以又称为轻型进程(Light-Weight Process),相应的把传统进程称为重型进程(Heavy-Weight Process)

在这里插入图片描述

1)调度

在这里插入图片描述
类比:

进程切换:像搬家(需要打包整个家的物品,耗时耗力)。

线程切换:像换房间(只需带个人物品,快速方便)。

2)并发性

在这里插入图片描述
在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行

3)拥有资源

在这里插入图片描述
示例:

进程A和进程B各自拥有独立的内存空间,无法直接访问对方的变量。

线程T1和T2共享进程的内存空间,T1修改全局变量x,T2可直接访问。

4)系统开销

在这里插入图片描述

在一些操作系统中,线程的切换、同步和通信都无须操作系统内核的干预

(3)线程的属性

线程是操作系统中能够进行独立调度和分派的基本单位,具有轻型实体、可并发执行以及共享进程资源等属性。

轻型实体

  • 资源占用少
  • 创建和切换开销低
  • 管理成本低

独立调度和分派的基本单位

  • 响应性高:由于线程的调度粒度更细,程序的响应性更高。例如,在图形用户界面(GUI)程序中,主线程可以处理用户输入,而工作线程可以执行后台任务,两者互不干扰。

可并发执行

  • 甚至允许一个进程中的所有线程都能并发执行,不同进程中的线程也可能并发执行

共享进程资源

  • 共享地址空间
  • 共享文件描述符
  • 共享全局变量
  • 共享其他资源(如信号处理程序、当前工作目录等)

(4)线程的状态

1)状态参数

  • 寄存器状态
  • 堆栈
  • 线程运行状态
  • 优先级
  • 线程专有寄存器
  • 信号屏蔽

eg Java 中线程状态的枚举类 Thread.State 的参数
在这里插入图片描述

2)线程运行状态

eg:

  • 执行状态
  • 就绪状态
  • 阻塞状态

eg:

[NEW] -> [RUNNABLE] -> [RUNNING] -> [TERMINATED]
             |
             v
        [BLOCKED]
             |
             v
        [WAITING] / [TIMED_WAITING]
  • NEW:线程已创建,但未启动。
  • RUNNABLE:线程已启动,正在等待 CPU 执行。
  • RUNNING:线程正在执行代码。
  • BLOCKED、WAITING、TIMED_WAITING:线程处于等待状态。
  • TERMINATED:线程执行完毕。

(5)线程的创建和终止

在多线程 OS 环境下,应用程序在启动时,通常仅有一个线程在执行,该线程被人们称为“初始化线程”

根据需要可以再去创建若干个线程。

eg java 中

创建线程

  • 使用 Thread 类或 Runnable 接口创建线程。
  • 调用 start() 方法启动线程。

终止线程

  • 自然终止:run() 方法执行完毕。
  • 优雅终止:使用标志位让线程主动退出。
  • 避免使用 Thread.stop()(强制终止,可能导致资源泄露、死锁或数据不一致。)

(6)多线程 OS 中的进程

多线程 OS 中的进程有以下属性

1)作为系统资源分配的基本单位

独立资源空间:每个进程拥有独立的地址空间、全局变量、文件描述符等资源。进程间的资源互不共享,保证了进程的隔离性和安全性。

资源管理:操作系统为每个进程分配独立的资源,例如内存、文件句柄、I/O设备等。进程间的通信需要通过进程间通信(IPC)机制实现。

2)可包括多个线程

线程共享进程资源:同一进程中的多个线程共享进程的地址空间、全局变量、文件描述符等资源。线程间的通信更加高效,因为它们可以直接访问共享内存。

独立执行路径:每个线程有自己的程序计数器(PC)、寄存器集合和栈空间,用于保存线程的执行上下文。线程可以独立调度,执行不同的代码路径。

3)进程不是一个可执行的实体

是把线程作为独立运行的基本单位

进程可以处于就绪、运行、阻塞等状态。线程的状态变化会影响进程的状态,例如,当进程中的所有线程都阻塞时,进程可能进入阻塞状态。

反之,把某个进程挂起时,该进程中所有线程也都将被挂起

6.2、线程间的同步和通信

在多线程编程中,线程间的同步和通信是确保程序正确性和高效性的关键。同步用于协调线程对共享资源的访问,避免竞争条件(Race Condition)和数据不一致性;通信则用于线程之间交换信息,协调它们的执行顺序。

(1)互斥锁(Mutex)

定义

  • 互斥锁(Mutex,Mutual Exclusion)是一种用于保护共享资源的同步机制。它确保同一时间只有一个线程可以访问被保护的代码块或资源。

工作原理

  • 当一个线程需要访问共享资源时,它首先尝试获取互斥锁。
  • 如果锁未被其他线程持有,则该线程成功获取锁并访问资源。
  • 如果锁已被其他线程持有,则该线程将被阻塞,直到锁被释放。
  • 访问完资源后,线程释放锁,允许其他线程获取。

特点

  • 互斥性:保证同一时间只有一个线程可以访问受保护的资源。
  • 简单易用:适用于保护小块代码或简单数据结构。

示例(伪代码)

pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);

void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex);
    // 访问共享资源
    pthread_mutex_unlock(&mutex);
    return NULL;
}

注意事项

  • 避免死锁:确保锁的获取和释放顺序一致,避免循环等待。
  • 减少锁的持有时间:长时间持有锁会降低并发性。

(2) 条件变量(Condition Variable)

每一个条件变量通常都与一个互斥锁一起使用

定义:

  • 条件变量用于线程间的通信,允许一个或多个线程等待某个条件成立,而另一个线程在条件成立时通知等待的线程。

工作原理

  • 条件变量通常与互斥锁结合使用。
  • 线程在等待某个条件时,释放互斥锁并进入等待状态。
  • 当条件发生变化时,另一个线程通知等待的线程,等待的线程被唤醒并重新获取互斥锁。

特点

  • 线程通信:允许线程协调执行顺序。
  • 减少忙等待:避免线程不断检查条件,浪费CPU资源。

比喻

  • 想象你在餐厅排队等位,服务员(线程)会告诉你“有空桌时通知你”(条件变量)。
  • 你(线程)先挂起(进入等待状态),当有空桌时,服务员(线程)喊一声“有空桌了”(发出信号),你(线程)被唤醒,继续执行(比如去就座)。

(3)信号量(Semaphore)

定义

  • 信号量是一种用于控制对共享资源访问的同步机制,它可以用于实现互斥和同步。

工作原理

  • 信号量维护一个计数器,表示可用资源的数量。
  • 线程在访问资源前,尝试对信号量执行wait操作(P操作),如果计数器大于0,则计数器减1,线程继续执行;否则,线程被阻塞。
  • 线程在释放资源时,对信号量执行signal操作(V操作),计数器加1,并可能唤醒一个等待的线程。

特点

  • 灵活性:可以用于实现更复杂的同步场景,如生产者-消费者问题。
  • 计数功能:允许同时有多个线程访问资源

示例

sem_t semaphore;
sem_init(&semaphore, 0, 3);  // 初始化信号量,允许3个线程同时访问

void* thread_function(void* arg) {
    sem_wait(&semaphore);  // 尝试访问资源
    // 访问共享资源
    sem_post(&semaphore);  // 释放资源
    return NULL;
}

注意事项

  • 信号量的初始值决定了同时可以访问资源的线程数
  • 避免信号量值溢出或下溢。

实际应用中的选择

  • 互斥锁:适用于需要保护小块代码或简单数据结构的场景。
  • 条件变量:适用于线程间需要协调执行顺序的场景,如生产者-消费者问题。
  • 信号量:适用于需要控制多个线程同时访问共享资源的场景,如资源池管理。

6.3、线程的实现方式

线程的实现方式主要分为三种:内核支持线程(KST, Kernel Supported Threads)、用户级线程(ULT, User Level Threads)以及组合方式(前两种方式的结合)。

(1)内核支持线程(KST, Kernel Supported Threads)

定义

  • 内核支持线程是在内核的支持下运行的线程,其创建、阻塞、撤销和切换等操作都在内核空间内完成。

特点

  • 内核管理:内核为每个线程设置一个线程控制块(TCB),通过TCB来感知和控制线程。
  • 并发执行:在多处理器系统中,内核能够同时调度同一进程中的多个线程并发执行。
  • 阻塞处理:当一个线程阻塞时,内核可以调度该进程中的其他线程继续执行,从而提高系统的并发性。
  • 切换开销:由于线程的切换需要在内核态和用户态之间进行,因此切换开销相对较大

优点

  • 能够充分利用多处理器系统的优势,提高系统的并发性。
  • 内核对线程的管理更加直接和高效。

缺点

  • 线程切换开销较大,因为需要经历用户态到内核态的切换。
  • 内核需要为每个线程分配资源,可能增加系统的资源消耗。

(2)用户级线程(ULT, User Level Threads)

定义

  • 用户级线程是在用户空间中实现的线程,其创建、撤销、同步和通信等操作都在用户空间中完成,无需内核的直接支持。

特点

  • 用户管理:用户级线程的调度通常以进程为单位进行,但具体的调度算法可以由用户自定义。
  • 切换开销小:由于线程的切换在用户空间中进行,因此切换开销相对较小。
  • 阻塞影响:当一个线程阻塞时,其他所有线程都可能被阻塞(这取决于具体的实现和调度策略),因为操作系统感知不到用户级线程的存在。

优点

  • 线程切换开销小,提高了系统的响应速度(不需要转换到内核空间)。
  • 用户可以根据具体需求自定义线程调度算法。

缺点

  • 当一个线程阻塞时,可能影响其他线程的执行
  • 无法充分利用多处理器系统的优势,因为用户级线程的调度以进程为单位

eg:进程 A 中包含了一个用户级线程,进程 B 包含有 100 个用户级线程,设置了用户级线程的系统,调度以进程为单位进行,在采用轮转调度算法时,A中线程运行时间将是 B 中各线程运行时间的 100 倍

假如系统中设置的是内核支持线程,则调度便是以线程为单位进行的,在采用轮转法调度时,进程 B 可获得的 CPU 时间是进程 A 的 100 倍

(3)组合方式

定义

  • 组合方式是内核支持线程和用户级线程的结合,旨在充分利用两者的优点。

实现方式

  • 多对一模型:将多个用户级线程映射到一个内核支持线程上。这种方式的优点是开销小、效率高,但缺点是当一个线程阻塞时,整个进程都会被阻塞。
  • 一对一模型:每个用户级线程都映射到一个内核支持线程上。这种方式的优点是当一个线程阻塞时,允许其他线程继续运行,且允许多个线程并行地运行在多处理机系统上。但缺点是开销较大。
  • 对多模型:将多个用户级线程映射到同样数量或者更少数量的内核支持线程上。这种方式结合了上述两种模型的优点,可以根据实际情况调整内核控制线程数目。

优点

  • 充分利用了内核支持线程和用户级线程的优点。
  • 提高了系统的并发性和响应速度。

缺点

  • 实现复杂度较高。
  • 可能需要更多的系统资源来支持多种线程模型。

6.4、线程的实现

不论是进程还是线程,都必须直接或间接地取得内核的支持

(1)内核支持线程(Kernel-Level Threads)

实现方式:

  • 内核级线程由操作系统内核直接管理。
  • 每个线程在内核中都有对应的线程控制块(TCB),内核负责线程的调度、切换和管理。

应用场景:

  • 适用于需要充分利用多核处理器、对线程管理要求较高的应用,如服务器、数据库等。

在仅设置了内核支持线程的 OS 中,一种可能的线程控制方法是,系统在创建一个新进程时,便为它分配了一个任务数据区 PTDA(Per Task Data Area),用于存储与该进程相关的资源信息。PTDA 包含若干个线程控制块(TCB)空间,用于管理进程中的线程。

在这里插入图片描述

(2)用户级线程(User-Level Threads)

实现方式:

  • 用户级线程由用户空间的线程库管理,内核并不知道用户级线程的存在。
  • 线程切换在用户空间完成,不需要内核介入。

应用场景:

  • 适用于对性能要求较高、线程阻塞较少的应用,如某些高性能计算、实时系统等。

用户线程是在用户空间实现的,所有用户级线程都具有相同的结构,它们都运行在一个中间系统的上面。当前有两种方式实现中间系统

  • 运行时系统(Running System)
  • 内核控制线程,这种线程又称为轻型进程 LWP(Light Weight Process)

LWP(Light Weight Process) 是操作系统中一种实现多任务的方法,属于线程调度的核心机制。与普通进程相比,LWP 共享内存地址空间和文件资源,但拥有独立的任务执行流。

在这里插入图片描述


在这里插入图片描述

(3)用户级线程和内核控制线程的连接

在这里插入图片描述

一对一模型适用于需要高效并行执行且对线程数量要求不高的场景。eg:Windows线程

多对一模型适用于轻量级、高并发的场景,但无法利用多核CPU。eg:Green Threads:早期Java虚拟机(如旧版JVM)使用的用户级线程实现。

多对多模型结合了前两者的优点,是现代操作系统和编程语言的主流选择,如Go语言的Goroutines。


更多有趣的计算机知识和代码示例,可参考【Programming】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2331246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单reactor实战

前言&#xff1a;reactor作为一种高性能的范式&#xff0c;值得我们学习 本次目标 实现一个基于的reactor 具备echo功能的服务器 核心组件 Reactor本身是靠一个事件驱动的框架,无疑引出一个类似于moduo的"EventLoop "以及boost.asio中的context而言&#xff0c;不断…

初阶C++笔记第一篇:C++基础语法

虽然以下大多数知识点都在C语言中学过&#xff0c;但还是有一些知识点和C语言不同&#xff0c;比如&#xff1a;代码格式、头文件、关键字、输入输出、字符串类型等... 1. 初识C 1.1 第一个C程序 编写C分为4个步骤&#xff1a; 创建项目创建文件编写代码运行程序 C的第一条…

无需libpacp库,BPF指令高效捕获指定数据包

【环境】无libpacp库的Linux服务器 【要求】高效率读取数据包&#xff0c;并过滤指定端口和ip 目前遇到两个问题 一是手写BPF&#xff0c;难以兼容&#xff0c;有些无法正常过滤二是性能消耗问题&#xff0c;尽可能控制到1% 大方向&#xff1a;过滤数据包要在内核层处理&…

react实现上传图片到阿里云OSS以及问题解决(保姆级)

一、优势 提高上传速度&#xff1a;前端直传利用了浏览器与 OSS 之间的直接连接&#xff0c;能够充分利用用户的网络带宽。相比之下&#xff0c;后端传递文件时&#xff0c;文件需要经过后端服务器的中转&#xff0c;可能会受到后端服务器网络环境和处理能力的限制&#xff0c;…

Python 字典和集合(常见的映射方法)

本章内容的大纲如下&#xff1a; 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响&#xff08;什么样的数据类型可作为键、不可预知的 顺序&#xff0c;等等&#xff09; 常见的映射方法 映射类型…

Matlab轴承故障信号仿真与故障分析

1.摘要 本文介绍了一个基于Matlab的轴承故障信号仿真与分析程序&#xff0c;旨在模拟和分析轴承内圈故障信号的特征。程序首先通过生成故障信号、共振信号和调制信号&#xff0c;添加噪声和离散化处理&#xff0c;构建模拟的振动信号&#xff0c;并保存相关数据。通过快速傅里…

Linux 进程 | 概念 / 特征 / 状态 / 优先级 / 空间

注&#xff1a; 本文为 “Linux 进程” 相关文章合辑。 未整理去重。 Linux 进程概念&#xff08;精讲&#xff09; A little strawberry 于 2021-10-15 10:23:55 发布 基本概念 课本概念&#xff1a;程序的一个执行实例&#xff0c;正在执行的程序等。 内核观点&#xff…

重回全面发展亲自操刀

项目场景&#xff1a; 今年工作变动&#xff0c;优化后在一家做国有项目的私人公司安顿下来了。公司环境不如以前&#xff0c;但是好在瑞欣依然可以每天方便的买到。人文氛围挺好&#xff0c;就是工时感觉有点紧&#xff0c;可能长期从事产品迭代开发&#xff0c;一下子转变做项…

3D珠宝渲染用什么软件比较好?渲染100邀请码1a12

印度珠宝商 Mohar Fine Jewels 和英国宝石商 Gemfields 在今年推出了合作珠宝系列——「Emeralds in Full Bloom」&#xff0c;它的灵感源自花草绽放的春季田野&#xff0c;共有 39 件作品&#xff0c;下面这个以植物为主题的开口手镯就是其中一件。 在数字时代&#xff0c;像这…

【数据结构】邻接矩阵完全指南:原理、实现与稠密图优化技巧​

邻接矩阵 导读一、图的存储结构1.1 分类 二、邻接矩阵法2.1 邻接矩阵2.2 邻接矩阵存储网 三、邻接矩阵的存储结构四、算法评价4.1 时间复杂度4.2 空间复杂度 五、邻接矩阵的特点5.1 特点1解析5.2 特点2解析5.3 特点3解析5.4 特点4解析5.5 特点5解析5.6 特点6解析 结语 导读 大…

【嵌入式-stm32电位器控制以及旋转编码器控制LED亮暗】

嵌入式-stm32电位器控制LED亮暗 任务1代码1Key.cKey.hTimer.cTimer.hPWM.cPWM.hmain.c 实验现象1任务2代码2Key.cKey.hmain.c 实验现象2问题与解决总结 源码框架取自江协科技&#xff0c;在此基础上做扩展开发。 任务1 本文主要介绍利用stm32f103C8T6实现电位器控制PWM的占空比…

Uniapp 集成极光推送(JPush)完整指南

文章目录 前言一、准备工作1. 注册极光开发者账号2. 创建应用3. Uniapp项目准备 二、集成极光推送插件方法一&#xff1a;使用UniPush&#xff08;推荐&#xff09;方法二&#xff1a;手动集成极光推送SDK 三、配置原生平台参数四、核心功能实现1. 获取RegistrationID2. 设置别…

2025年常见渗透测试面试题-sql(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 SQLi 一、发现test.jsp?cid150 注入点的5种WebShell获取思路 1. 文件写入攻击 2. 日志文件劫持 3.…

【RabbitMQ】队列模型

1.概述 RabbitMQ作为消息队列&#xff0c;有6种队列模型&#xff0c;分别在不同的场景进行使用&#xff0c;分别是Hello World&#xff0c;Work queues&#xff0c;Publish/Subscribe&#xff0c;Routing&#xff0c;Topics&#xff0c;RPC。 下面就分别对几个模型进行讲述。…

StarRocks 助力首汽约车精细化运营

作者&#xff1a;任智红&#xff0c;首汽约车大数据负责人 更多交流&#xff0c;联系我们&#xff1a;https://wx.focussend.com/weComLink/mobileQrCodeLink/334%201%202/ffbe5 导读&#xff1a; 本文整理自首汽约车大数据负责人任智红在 StarRocks 年度峰会上的演讲&#xf…

痉挛性斜颈康复助力:饮食调养指南

痉挛性斜颈患者除了积极治疗&#xff0c;合理饮食也能辅助缓解症状&#xff0c;提升生活质量。其健康饮食可从以下方面着手&#xff1a; 高蛋白质食物助力肌肉修复 痉挛性斜颈会导致颈部肌肉异常收缩&#xff0c;消耗较多能量&#xff0c;蛋白质有助于肌肉的修复与维持。日常可…

mysql镜像创建docker容器,及其可能遇到的问题

前提&#xff0c;已经弄好基本的docker服务了。 一、基本流程 1、目录准备 我自己的资料喜欢放在 /data 目录下&#xff0c;所以老规矩&#xff1a; 先进入 /data 目录&#xff1a; cd /data 创建 mysql 目录并进入&#xff1a; mkdir mysql cd mysql 2、镜像查找 docke…

JavaEE——线程的状态

目录 前言1. NEW2. TERMINATED3. RUNNABLE4. 三种阻塞状态总结 前言 本篇文章来讲解线程的几种状态。在Java中&#xff0c;线程的状态是一个枚举类型&#xff0c;Thread.State。其中一共分为了六个状态。分别为&#xff1a;NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING, TERMI…

RuntimeError: Error(s) in loading state_dict for ChartParser

一 bug错误 最近使用千问大模型有一个bug&#xff0c;报错信息如下 raise RuntimeError(Error(s) in loading state_dict for {}:\n\t{}.format( RuntimeError: Error(s) in loading state_dict for ChartParser:Unexpected key(s) in state_dict: "pretrained_model.em…

2025 年安徽交安安全员考试:利用记忆宫殿强化记忆​

安徽考生在面对交安安全员考试繁杂的知识点时&#xff0c;记忆宫殿是强大的记忆工具。选择一个熟悉且空间结构清晰的场所作为记忆宫殿&#xff0c;如自己居住的房屋。将房屋的不同区域&#xff0c;如客厅、卧室、厨房等&#xff0c;分别对应不同知识板块&#xff0c;像客厅对应…