首页 > 其他分享 >09-同步

09-同步

时间:2023-10-28 18:26:38浏览次数:33  
标签:同步 Lock 09 临界 flag 线程 进程 等待

09-同步

一、背景

到目前为止

  • 多道程序设计(multi-programming): 现代操作系统的重要特性
  • 并行很有用(为什么?)多个并发实体CPU(s) I/O 用户
  • 进程/线程: 操作系统抽象出来用于支持多道程序设计
  • CPU调度:实现多道程序设计的机制
  • 调度算法 -不同的策略
    接下来
  • 协同多道程序设计和并发问题

独立的线程

  • 不和其他线程共享资源或状态
  • 确定性->输入状态决定结果
  • 可重现->能够重现起始条件
  • 调度顺序不重要

合作线程

  • 在多个线程中共享状态
  • 不确定性
  • 不可重现

不确定性和不可重现意味着bug可能是间歇性发生的

进程/线程, 计算机/设备需要合作
优点1:共享资源

  • 一台电脑,多个用户
  • 嵌入式系统(机器人控制:手臂和手的协调)
    优点2:加速
  • I/O操作和计算可以重叠
  • 多处理器-将程序分成多个部分并行执行
    优点3:模块化
  • 将大程序分解成小程序 以编译为例:gcc会调用cpp,cc1,cc2,as,ld
  • 使系统易于扩展

无论多个线程的指令序列怎样交替执行,程序都必须正常工作
多线程程序具有不确定性和不可重现的特点
不经过专门设计,调试难度很高

不确定性要求并行程序的正确性
先思考清楚问题,吧程序的行为设计清楚
切忌基于着手写代码,碰到问题再调试

一些概念

Race Condition(竞态条件)
系统缺陷:结果依赖于并发执行或者时间的顺序/时间

  • 不确定性
  • 不可重现
    如何避免竞态

原子操作 Atomic Operation

  • 原子操作是指一次不存在任何中断或失败的执行
    该执行成功结束
    或者根本没有执行
    并且不应该发现任何部分执行的状态
  • 实际上操作往往不是原子的
    有些看上去是原子操作
    连x++这样的简单语句,实际上是由3条指令构成的
    有时候甚至连单条机器指令都不是原子的 Pipeline,super-scalar, out-of-order, page fault

critical section(临界区)
临界区是指进程中的一段需要访问共享资源并且当另一个进程处于相应代码区域时便不会被执行的代码区域

Mutual exclusion(互斥)
当一个进程处于临界区并访问共享资源时,没有其他进程会处于临界区并且访问任何相同的共享资源

Dead lock(死锁)
两个或以上的进程,在相互等待完成特定任务,而最终没法将自身任务进行下去

Starvation(饥饿)
一个可执行的进程,被调度器持续忽略,以至于虽然处于可执行状态却不被执行

Lock(锁)
在门,抽屉等物体上加上保护性装置,使得外人无法访问物体内的东西,只能等待解锁后才能访问
Unlock(解锁)
打开保护性装置,使得可以访问之前被锁保护的物体类的东西
DeadLock(死锁)
A拿到锁1,B拿到锁2,A想继续拿到锁2后再继续执行,B想拿到锁1后再继续执行。导致A和B谁也无法继续执行

二、临界区

互斥
同一时间临界区中最多存在一个线程
Progress
如果一个线程想要进入临界区,那么它最终会成功
有限等待
如果一个线程i处于入口区,那么在i的请求被接受之前,其他进程进入临界区的时间是有限的
无忙等待(可选)
如果一个进程在等待进入临界区,那么在它可以进入之前会被挂起

如何实现对临界区代码的保护?有以下三种方法

三、方法1:禁用硬件中断

没有中断。没有上细问切换,因此没有并发

  • 硬件将中断处理延迟到中断被启用之后
  • 大多数现代计算机体系结构都提供指令来完成

进入临界区

  • 禁用中断

离开临界区

  • 开启中断

一旦中断被禁用,线程就无法被停止

  • 整个系统都会为你停下来
  • 可能导致其他线程处于饥饿状态

要是临界区可以任意长怎么办

  • 无法限制响应中断所需的时间(可能存在硬件影响)

要小心使用
不适用于多CPU的情况

四、方法2:基于软件的解决方法

Peterson 算法(针对两个进程)

do {
    flag[i] = TRUE;
    turn = j;
    while(flag[j] && turn ==j);
    CRITICAL SECTION
    flag[i] = FALSE;
    REMAINDER SECTION 
} while (TRUE)

Dekker 算法

flag[0]:=false flag[1]:=false turn :=0 // or 1
do {
    flag[i]=TRUE;
    while flag[j]=true {
        if turn!=i {
            falg[i]!= false;
            while turn != i {}
            flag[i]:=TRUE
        }
    }
    CRITICAL SECTION
    turn:=j
    flag[i]=TRUE
    REMAINDER SECTION
} while (TRUE)

Bakery 算法

N个进程的临界区

  • 进入临界区之前,进程接收一个数字
  • 得到数字最小的进入临界区
  • 如果进程Pi和Pj收到相同的数字,那么如果i<j, Pi先进入临界区,否则Pj先进入临界区
  • 编号方案总是按照枚举的增加顺序生成数字

Dekker算法(1965):第一个针对双线程例子的正确解决方案
Bakery算法(Lamport 1979): 针对n线程的临界问题解决方案
复杂:需要两个进程间的共享数据项
需要忙等待:浪费CPU时间
没有硬件保证的情况下无真正的软件解决方案: Peterson算法需要原子的LOAD和STORE指令

五、方法3:更高级的抽象

  • 硬件提供了一些原语
    像中断禁用,原子操作指令等
    大多数现代体系结构都这样
  • 操作系统提供更高级的编程抽象来简化并行编程
    例如:锁,信号量
    从硬件原语中构建
  • 锁是一个抽象的数据结构
    一个二进制状态(锁定、解锁),两种方法
    Lock::Acquire() -锁被释放前一直等待,然后得到锁
    Lock::Release() -释放锁,唤醒任何等待的进程
  • 使用锁来编写临界区
    前面的例子变得简单起来
      lock_next_pid->Acquire();
      new_pid = next_pid++;
      lock_next_pid->Release();
    
  • 大多数现代体系结构都提供特殊的原子操作指令
    通过特殊的内存访问电路
    针对单处理器和多处理器
  • Test-and-Set测试和置位
    从内存中读取值
    测试该值是否为1(然后返回真或假)
    内存值设置为1
  • 交换
    交换内存中的两个值
    boolean TestAndSet(boolean *target) {
        boolean rv = *target;
        *target = TRUE;
        return rv;
    }
    
    void Exchange(boolean *a, boolean *b) {
        boolean temp = *a;
        *a = *b;
        *b = temp;
    }
    

使用 TestAndSet 方法实现锁

class Lock {
    int value=0;
}

Lock::Acquire() {
  while (test-and-set(value));//spin        
}
// 如果锁被释放,那么test-and-set读取0并将值设置为1 -> 锁被设置为忙并且需要等待完成
// 如果锁处于忙状态,那么test-and-set读取1并将值设置为1 -> 不改变所得状态并且需要循环(自旋spin)

Lock::Release() {
  value=0;        
}
  • 使用忙等待的锁
    就像上面使用test-and-set实现的锁一样
    线程在等待的时候消耗CPU周期

如何做的更好?
无忙等待

class Lock {
    int value = 0;
    WaitQueue q;
}

Lock::Acquire(){
    while (test-and-set(value)){
        add this TCB to wait queue q;
        schedule();
    }
}

Lock::Release() {
    value=0;
    remove one thread t from q;
    wakeup(t);
}

使用 change方法实现锁

共享数据(初始化为0)
int lock= 0;

线程 Ti

  int key;
  do {
      key=1;
      while(key==1) exchange(lock,key);
          critical section
      lock = 0;
          remainder section
  }
  • 优点
    适用于单处理器或者共享主存的多处理器中任意数量的进程
    简单并且容易证明
    可以用于支持多临界区

  • 缺点
    忙等待消耗处理器时间
    当进程离开临界区并且多个进程在等待的时候可能导致饥饿
    死锁
    如果一个低优先级的进程拥有临界区并且一个该优先级的进程也需求,那么高优先级进程会获得处理器并等待临界区

  • 锁是更高等级的编程抽象
    互斥可以使用锁来实现
    通常需要一定等级的硬件支持

  • 常用的三种实现方法
    禁用中断(仅限于单处理器)
    软件方法(复杂)
    原子操作指令(单处理器或多处理器均可)

  • 可选的实现内容
    有忙等待
    无忙等待

标签:同步,Lock,09,临界,flag,线程,进程,等待
From: https://www.cnblogs.com/Oh-mydream/p/17794420.html

相关文章

  • Linux中设置NTP时间同步服务器的方法
    概括:在Linux中设置NTP时间同步服务器是确保多台主机之间时间同步的重要步骤。本文将从四个方面详细阐述Linux中设置NTP时间同步服务器的方法,包括安装NTP、配置NTP客户端、配置NTP服务器以及常见问题及其解决方法。1、安装NTP安装NTP是为了确保Linux主机能够正常运行时间同......
  • [ARC098F] Donation
    质量很大,孩子很喜欢......
  • Java基础 同步方法
    同步代码块就是把一段代码给锁起来,这样就可以解决多线程操作共享数据时带来的数据安全问题但是如果我们想要把一个方法里面所有的代码全都锁起来,就没有必要用同步代码块了,我们可以直接把synchronized加在方法上,这个方法就叫做同步方法 同步方法的格式:修饰符 synchroniz......
  • Java基础 同步代码块
    同步代码块:利用同步代码块把操作共享数据的代码给锁起来,让同步代码块里面的代码是轮流去执行的 格式:synchronized(锁对象){   操作共享数据的代码} 细节:1.在最初,锁的状态是默认打开的,如果有一个线程进去了,锁就会自动关闭2.当锁里面全部代码都执行完毕了,线程......
  • day 2 数组 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵 Ⅱ
    977.有序数组的平方题目链接:977.有序数组的平方视频教程文章教程思路最直观的解法:暴力解题,每个数先平方,然后再快速排序,时间复杂度为O(n+nlogn)规律:该数组本身是非递减顺序,在平方后其实依然有顺序,左右两边大中间小。双指针利用观察到的规律,可以利用双指针在数......
  • 新手教程系列:群晖 Synology Drive教程,如何实现文件同步与备份?
    SynologyDrive是群晖NAS的一款文件同步和共享工具,提供了非常完善的功能,您可以轻松地对文件进行分类、归档、共享等操作,也可以在多个设备之间同步文件、备份文件、共享文件,包括电脑、手机、平板等设备。总的来说,使用SynologyDrive的好处是可以方便快捷地在不同设备之间同步文件,保......
  • win11 打印机故障 0x000000709
    0x000000709无需删除任何更新,新建打印机凭证即可;  无需重启电脑,再次连接打印机 ......
  • 代码随想录算法训练营第一天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩
    今日学习的文章链接和视频链接https://programmercarl.com/0977.有序数组的平方.htmlhttps://programmercarl.com/0209.长度最小的子数组.htmlhttps://programmercarl.com/0059.螺旋矩阵II.html977.有序数组的平方菜鸡刚开始只会暴力,记录一下双指针:varsortedSquares=......
  • https://www.modb.pro/db/1717179181560324096 --转载 Oracle 批量更新(BULK)优化技巧
    面对一个需要更新大量数据的任务,我平时的处理方法是通过循环,每N行提交来完成这个任务。这样做的两个主要原因:1、频繁地提交大量小事务比处理和提交一个大事务更快,也更高效2、没有足够的UNDO空间今天在学到了一种新的解决思路,在此记录一下方便后面使用。  假设我们有一个表T,......
  • ntp时间同步
    一、安装ntp#既可做服务端也可做客户端yuminstall-yntp#只同步yuminstall-yntpdate#开启服务,让其他客户端与本机同步,注意防火墙状态systemctlstartntpd#开机自启systemctlenablentpd#防火墙开启相关端口firewall-cmd--zone=public--permanent--add-......