操作系统 进程相关

本文围绕进程、线程、协程展开,介绍了它们的定义、资源、切换开销、通信与同步方式。还阐述了Linux进程通信、调度、状态切换等内容,分析了守护、僵尸、孤儿进程,以及中断、异常、死锁问题。最后讲解零拷贝技术和典型锁机制,给出多线程优化手段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 进程、线程、协程

定义

【Are u OKay?——协程、线程、进程】 https://www.bilibili.com/video/BV1Wr4y1A7DS/?share_source=copy_web&vd_source=1e4d767755c593476743c8e4f64e18db

高并发:线程池,不要无休止的创建线程。--> task很小很快,thread需要切换(中断)-->协程

拥有资源

切换过程、开销

进程切换:

  1. 上下文保存(保存当前进程状态): 当操作系统决定切换到另一个进程时,首先需要保存当前进程的上下文信息,包括寄存器的状态、程序计数器、内存页表等。

  2. 切换到内核模式: 进程切换通常涉及从用户模式切换到内核模式,以便操作系统能够执行敏感的指令并更改进程的状态。

  3. 调度新进程: 操作系统选择要切换到的新进程,将其上下文信息加载到 CPU 寄存器和内存管理单元中。

  4. 切换到用户模式: 切换到新进程的用户模式,允许其执行。

在任务切换的过程中,通常会涉及到系统调用。系统调用是用户程序与操作系统之间进行通信的一种方式,用于请求操作系统提供服务。在任务切换中,以下情况可能触发系统调用:

  1. 上下文保存: 将当前进程的上下文信息保存到内存中,可能涉及到对内存的写操作,这可能需要调用操作系统提供的服务。

  2. 切换到内核模式: 用户程序切换到内核模式通常需要通过中断或异常来触发,这会涉及到一些与特权级别相关的系统调用,例如进入内核模式的中断服务例程。

  3. 调度新进程: 选择和调度新进程也可能涉及到系统调用,例如获取进程列表、更新进程状态等。

通信、并发

进程是应用程序/程序的执行副本,进程要管理硬件资源、CPU资源、文件资源、内存分页等,执行只需要CPU和内存。进程来回切换消耗资源,所以抽象出一个更小的单位线程,当一个程序启动以后(进程),会产生一个主线程,操作系统将计算资源不给进程,而是直接给主线程。进程是资源管理的单位,线程是程序执行的单位,线程只需要执行程序。操作系统的调度线程的执行,一个一个线程排队执行,每个线程执行时都有一个时间片,当时间片执行完了以后,切换下一个线程执行。程序执行产生一个进程,这个进程都会有一个主线程。但是操作系统调度的是自己的线程,自己的线程表,程序员在用户空间创建线程,但是真正执行的是操作系统的线程。操作系统的线程和用户线程是映射关系,也就是说,操作系统的线程才是真正的线程,程序员并不能直接执行直接的线程,必须要挂靠到操作系统的线程执行。高并发的场景下,会有很多task,为每个task创建一个线程(线程对象)很占用内存空间,每个线程都对应一个操作系统的线程(内核线程),这样操作系统忙不过来。所以设计了线程池技术,溢出线程池怎么办,让task排队(线程会回收到线程池)。

2 Linux 进程通信方式

管道

消息队列

  1. 内核中的链表: 消息队列通常在内核中维护一个链表,用于存储进程发送的消息。每个消息都是链表中的一个节点,包含了消息内容、发送者、接收者等信息。这样的设计使得内核能够高效地管理和调度消息。

  2. 系统调用: 在Linux系统中,消息队列的相关操作是通过系统调用来实现的。

共享内存

基于虚拟内存实现,不需要走系统调用。往往配合信号量

信号量(同步,限制临界资源)

pv操作

套接字

信号

3 线程通信

信号

锁机制

条件变量

信号量

4 Linux 同步

  • POSIX信号量:可用于进程同步,也可用于线程同步。

  • POSIX互斥锁 + 条件变量:只能用于线程同步。

5 进程同步

  1. 互斥锁(Mutex):

    • 使用互斥锁来确保一次只有一个进程能够进入临界区(一段关键代码)。
    • 进入临界区前先尝试获得锁,如果锁已经被其他进程占用,则等待。
  2. 信号量(Semaphore):

    • 信号量是一种更为通用的同步工具,可以用来实现互斥和合作。
    • 可以用于控制对共享资源的访问,也可以用于进程之间的通信。

读者写者问题

允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写操作同时发生。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define N 100
typedef int semaphore;

semaphore mutex = 1;    // 互斥信号量,用于对临界区的访问进行互斥
semaphore empty = N;    // 表示缓冲区中的空槽位数量
semaphore full = 0;     // 表示缓冲区中的已有数据项数量

// 生产者函数
void producer() {
    while (1) {
        int item = produce_item();  // 生产一个数据项

        down(&empty);   // 等待缓冲区有空槽位可用
        down(&mutex);   // 进入临界区前先获取互斥锁

        insert_item(item);  // 将数据项插入缓冲区
        up(&mutex);         // 退出临界区,释放互斥锁
        up(&full);          // 增加已有数据项数量
    }
}

// 消费者函数
void consumer() {
    while (1) {
        down(&full);   // 等待缓冲区中有数据项可用
        down(&mutex);  // 进入临界区前先获取互斥锁

        int item = remove_item();  // 从缓冲区中移除数据项
        consume_item(item);        // 消费数据项

        up(&mutex);  // 退出临界区,释放互斥锁
        up(&empty);  // 增加空槽位数量
    }
}
  1. 条件变量(Condition Variable):

    • 条件变量用于在某个条件得到满足之前使线程等待,只有当条件满足时,才唤醒等待的线程。
    • 通常与互斥锁一起使用,以确保在检查条件和等待/唤醒之间的操作是原子的。
  2. <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值