📂 操作系统 - Operating System / Chapter III 并发 / Section 1 线程 / 1-1 并发与线程

并发:介绍

2026-05-15
#OS
  • 新的抽象:线程

    • 线程是什么

      • 在经典观念中,一个程序只有一个执行点一个程序计数器,用来存放要执行的指令),但多线程(Multi-threaded)程序则有多个执行点多个程序计数器
    • 线程与进程的异同

      • 多线程类似于多进程,不过不同在于:多个线程共享同一块地址空间
      • 对于线程调度CPU也需要进行上下文切换
        • 对于进程,我们需要将进程状态保存至进程控制块(PCB, Process control block)
        • 而对于线程,我们则需要线程控制块(TCB, Thread control block)
      • 对于地址空间中的内容,单线程程序只会有一个栈,而多线程程序会有多个栈
        • 每个线程会有一个自己的栈,用于存放线程自己的东西,这些栈也被称为线程本地(Thread-local)存储
  • 并发的问题:不可控的调度

    • 多线程程序中的问题

      #include <iostream>
      #include <thread>
      
      // 全局变量cnt,两个线程都会对它进行修改
      int cnt = 0;
      
      // 线程函数,每个线程都会执行这个函数来增加cnt的值
      void increaseThreadFunction() {
      	// 每个线程都执行1000000次“给cnt+1”的操作
      	for (int i = 0; i < 1000000; i++) {
      		cnt++;
      	}
      }
      
      // 主函数,创建两个线程来执行增加cnt的操作,并等待它们完成
      int main() {
      	// 创建两个线程,都执行increaseThreadFunction函数
      	std::thread thread_1(increaseThreadFunction);
      	std::thread thread_2(increaseThreadFunction);
      
      	// 等待两个线程执行完毕
      	thread_1.join();
      	thread_2.join();
      
      	// 当两个线程都执行完毕后,输出cnt
      	std::cout << "cnt = " << cnt << std::endl;
      	// 最终输出的cnt值可能小于2000000
      
      	// 程序结束,返回值为0
      	return 0;
      }
      
      • 实际输出:
        cnt = 1123662
        
      • 这是因为某个操作在执行时发生了上下文切换,导致结果被错误的计算,例如
        1. 线程A线程B被创建,假设CPU让线程A先开始运行
        2. A在内存中拿到了cnt的值,此时为0,然后在CPU中进行了运算“0+1”,得到结果为1
        3. 正当线程A要用1覆盖掉内存中cnt的值时,操作系统给线程A叫停了,要去执行线程B
        4. 线程B就开始运行:取指令、取cnt的值、0+1=1,得到结果为1
        5. 线程B将结果“1”在内存中覆盖掉原先的cnt
        6. 线程B结束,接下来线程A运行:线程A计算的结果是1,于是现在,线程A就用1覆盖cnt的值
        7. 结果,cnt为1,而不是2
  • 原子性愿望

    • 为了防止并发的不可控问题,我们需要一条更加强大的指令,这个指令是以原子方式(Atomically) 执行的
    • 一个以原子方式(Atomically) 执行的指令是在被中断时,要么已经执行完毕,要么根本没有运行,也就是“全部或没有
    • 这些指令的粒度需要比较小,它们的集合是同步原语(Synchronization primitive)
  • 并发术语

    • 临界区

      • 临界区(Critical section)访问共享资源一段代码,资源通常是一个变量或一个数据结构
    • 竞态条件

      • 竞态条件(Race condition) 出现在当多个执行线程大致同时进入临界区时。此时它们都试图更新共享的资源,导致了意料之外的结果
    • 不确定性

      • 一个程序由一个或多个竞态条件组成,运行的结果是不确定的,这就是一个不确定性(Indeterminate) 程序
    • 互斥执行

      • 程序应当使用一些互斥(Mutual exclusion)原语来保证一时间只有一个线程进入临界区避免产生竞态,从而产生确定的结果输出