操作系统哲学原理(线程原理)

$7 线程原理

  • 为什么需要线程
    进程有需要同时做多件事情的需求,他是线程的分身,每个线程本质上是一样的 都拥有相同的程序文本, 但是也有不同的地方 执行的上线文不一样,可以说是进程里面的一个执行序列
  • 线程管理:
  • 线程块中维护线程的信息,一般包含寄存器 计数器 状态字 栈,线程和线程之间的共享的资源 不放在线程块中
  • 一般os管理进程表, 线程块是在os中管理 还是在进程中管理呢, 前者是内核态 后者是用户态。前者优点是 用户省心了 缺点是需要消耗更多宝贵的为os分配的空间 陷入内核态太频繁 效率也会较低,而且需要改操作系统才能完成; 后者不存在前者的缺点, 却给用户除了很大的难题, 既要考虑什么时候让出cpu给其他进程, 有需要考虑阻塞了怎么办,管理困难 又 容易出错。最终是结合内核态和用户态两种方式 进行管理, 但是会减少陷入内核态的线程数量, 即将线程分组, 内核态管理线程组,管理阻塞的情况,用户态管理不阻塞的情况。
  • 用户态管理进程的探索
  • 提前预判阻塞, os中提供一个wrap, 每次进入线程钱先用wrap检查是否可能阻塞, 如果会阻塞 就去执行其他线程, 这里存在一个隐患 就是有些线程可能永远不会被执行到
  • 调度器激活 基于上个方案的缺点 另一个方案就是 当cpu因为某个进程中的线程阻塞而打算把控制权交给其他进程的时候,先别交给其他进程 而是询问执行进程是否有其他可执行的进程; 这个方案存在很大的bug, 即存在向上调用up-call的情况, 这是比较危险的, 违背了自上而下调用down-call的原则
  • 什么情况会导致陷入内核态:系统调用,进程发生中断或异常时候

$8 线程同步

  • 为什么要同步: 为了准确性和确定性, 两个进程如果共同读写一片内存空间, 因为代码执行顺序的原因 可能会导致内存中保存的结果存在不同,即不确定性 这不是希望看到,要尽量避免这种临界区的竞争现象
  • 什么是同步: 同步就是让多线程按照一定的规则执行, 使其正确性和效率都有迹可循,手段就是对线程之间的穿插实现控制。
  • 什么是临界区: 多线程争相执行同一段代码或访问同一资源的现象 叫做竞争,可能造成竞争的同一段代码或者同一资源 称为临界区。在单核的情况下 同一时刻不可能多个线程真的都在执行 但是却有可能都处在同一段代码中。
  • 协调:要防止竞争 就要防止多个线程同时进入临界区, 协调的目的就是实现具有竞争关系的线程互斥
  • 什么是互斥:
    • 不能有两个进程同时在临界区
    • 进程能够在任何数量和速度的cpu上正确执行
    • 在互斥区域外不能阻止另一个进程的运行
    • 进程不能无限制的等待进入临界区
  • 同步控制的原语:
    锁、sleep*weakup、信号量、管程、消息传递、栅栏

如何限制

  • 打标记: 控制单元是一条一条的指令
    依然存在都写的情况
if(noNote){setNote;dosomething;removeNote}

或者都不写的情况

setNote if(noOtherNote){dosomething} removeNote
  • 锁:控制单元是一组指令,可以解决都写或者都不写的情况, 但是会出现 忙等的情况, 为了减少等待时间 可以 锁+note的方式
    特证:
    • 初始为打开
    • 进入临界区lock
    • 出临界区unlock
    • 其他持有者必须等待
lock() dosomething() unlock()
lock()
checknote {setnote} 
unlock() 
checknote {dosomething() && removenote}
  • sleep&aweak: 可以解决都写 或 都不写的情况 ,也解决忙等的问题 但可能会出现不叫醒的情况,即形成‘死锁’
  • 消费者&生产者 && 商品count
    • count=0 消费者sleep
    • count=full 生产者sleep
    • 消费者的行为导致count=full-1 叫醒生产者
    • 生产者的行为导致count=1 叫醒消费者
    • 都不能自己改变自己的状态 只能被对方改变
 
max
count=0
producter:
  while true {
    if (count==max) {sleep}
    else {
      insert_item
      count+=1
      if (count==1) {weakup consumer}
  }

consumer:
  while true {
  if (count==0) {sleep}
  else {
    remove_item
    count-=1
    if (count==max-1) {weakup producer}
  }
}
}
  • 信号量: semaphore +up & down原语操作,semaphore=[0, 1]相当于锁

    • 原语down: if n>=1 n-1继续操作 else 等待在该信号量上
    • 原语up: n+1(将叫醒一个在该信号量上等待的线程)
  • 管程:monitor, 交给编译器处理线程同步问题

    • 作用: 监视线程或进程的同步操作, 解决信号量编程带来的困难和效率
    • 是程序语言级别的构造,把需要同步保护的代码 用monitor包起来, 当编译器将其翻译成低级低吗时候 遇到monitor的时候 就会将操作系统的原语添上, 管程保证了任何时候只有一个线程活跃在管程中;管程里使用了两种同步机制:锁+条件变量, wait+signal
  • 消息传递 不受单台计算机的限制 send & recive message是系统调用

    • 提供阻塞调用 和 非阻塞调用 两种方式
  • 栅栏:

    • 遇到栅栏的进程必须停下来 等清除栅栏之后才能推进;
    • 目的是 对一组进程进行协调, 有时候需要一组进程同时完成一个问题

$9

你可能感兴趣的:(操作系统哲学原理(线程原理))