算法设计与应用1-1 互斥算法

目录

  • Chap 1
    • 1.1互斥算法
      • 进程vs线程
      • 原子操作
      • 非原子操作期间的线程交换
      • 更新丟失
      • 临界区代码 Critical Sections of Code
      • 互斥算法的软件方法
        • 互斥算法
        • Dekker的算法:单标志法
        • 皮特森算法/Peterson Algorithm
        • 兰波特面包店算法/ Lamport's Bakery Algorithm
      • 互斥锁算法的硬件辅助
      • 线程旋转、阻塞和等待
      • 更多reference

Chap 1

1.1互斥算法

进程vs线程

  • 计算机需要能够同时执行多个任务
  • 可以并行执行,也可以在执行过程中反复切换任务,或者两者混合执行
  • 重量级进程有自己的代码、数据内存(全局变量和堆空间)和执行堆栈(局部变量和方法调用的激活记录)
    • 进程可以独立运行,提供对外部资源(如文件)的访问是协调的(如由操作系统)
  • 一个线程的执行(轻量级进程)共享代码和数据内存,但有自己的执行堆栈
    • 线程可以在同一代码的不同点运行
    • 需要仔细协调对全局变量/字段的访问(共享状态),以避免竞争条件
  • 不同的应用程序通常在不同的进程中执行,但在应用程序中,线程通常用于执行多个任务
    • 操作系统需要时间在进程之间上下文切换(必须保存/恢复进程状态每个开关)
    • 在线程之间切换比在进程之间切换快得多

原子操作

  • 一个原子操作,保证一个线程在一瞬间完全执行

  • 没有其他线程可见的中间状态

  • 不是很明显什么操作是原子的,比如x++不是原子的,因为它可能变成多个机器指令

    LOAD R,x
    INC R
    STORE R,x
    
  • 每个线程都有自己的执行堆栈,所以使用相同寄存器变量R的两个线程没有问题(它们在交换线程时被保存/恢复)

非原子操作期间的线程交换

  • 如果线程通过非原子操作进行交换,可能会发生“奇怪的事情”(竞态条件)

  • 如果一个线程试图读取一个全局变量/字段,而另一个线程正在更改它的值,读取的值取决于线程交换执行时的精确时间

    • 场景1:线程A开始执行x++,但线程B在线程A存储新值之前读取了x(线程B获得了原始值)

      LOAD R,x
      INC R
      							LOAD R,x
      STORE R,x
      
    • 场景2:线程A执行x++,然后线程B随后读取x(线程B获得增量值)

      LOAD R,x
      INC R
      STORE R,x
      							LOAD R,x
      

更新丟失

  • 当两个线程修改相同的共享状态时,也会发生更糟糕的“奇怪的事情”

  • 示例:线程A执行x++,而线程B也执行x++

    • 场景1:线程A执行x++然后线程B执行x++ (x加2)

      LOAD R,x
      INC R
      STORE R,x
      							LOAD R,x
      							INC R
      							STORE R,x
      
    • 场景2:线程A开始执行x++,但是线程B在线程A存储新值之前读取了x (x只加1)

      LOAD R,x
      INC R
      							LOAD R,x
      							INC R
      							STORE R,x
      STORE R,x
      
  • 被称为“更新丟失问题”

    • 即使多个线程执行代码来更新共享状态,有时只出现一些更新

    • 调试可能非常具有挑战性

    • 示例代码LostUpdate

      /**
         A class that demonstrates the lost update problem in concurrency
         by creating two threads that concurrently try to increment x
         each a total of ITE

你可能感兴趣的:(算法设计与应用基础,算法,java)