请选择 进入手机版 | 继续访问电脑版

[多线程] 线程概念简介 什么是线程 多线程上篇(七)

编程语言 编程语言 1721 人阅读 | 0 人回复

操作系统为了程序的并发执行引入了进程的概念,提高了资源的利用率以及吞吐量。

在20世纪 60年代人们提出了进程的概念后,在OS中一直都是以进程作为能拥有资源和独立运行的基本单位的。

直到 20 世纪 80 年代中期,人们又提出了比进程更小的能独立运行的基本单位——线程(Threads) 试图用它来提高系统内程序并发执行的程度,从而可进一步提高系统的吞吐量。

简言之,进程的概念,使之能够并发执行多道程序,线程的概念让你更好地并发执行程序,一个是能不能的问题,一个是更好的问题。

线程与进程对比

线程概念的发展 image.png 进程概念提出的目的就是为了多道程序并发执行,并发过程中必然意味着不断地进程调度任务切换,但是他又是资源分配的独立单位,也就是说他要背着资源来回跑。

举个例子: 办公室内,每个人都有一台电脑,电脑就是资源 然后大家经常需要不断地变换座位位置(比如大家都是哪里需要去哪里,客服缺人了,销售就顶一个过去) 每个人都抱着自己的电脑来回的换位置方便?还是大家只是人员走动,电脑就使用那个位置的电脑方便?

进程也是有些类似的道理,你带着这么多资源来回切换调度,必然会带来更多的时&&空开销。 所以创建了线程的概念,程序运行时所需的资源和程序的调度进行解耦

进程仍旧负责资源的独立分配,但是线程作为调度运行的独立单位,仅仅携带自身运行的必备的一丁点资源。

对比

线程具有许多传统进程所具有的特征,所以又称为轻型进程(Light-Weight Process)或进程元 相应地把传统进程称为重型进程(Heavy-Weight Process),传统进程相当于只有一个线程的任务。 在引入了线程的操作系统中,通常一个进程都拥有若干个线程,至少也有一个线程。 image.png

并发性

传统的OS系统,进程之间可以并发执行,引入线程概念的OS,不仅仅进程间可以并发执行,一个进程中的线程也可以并发执行,不同进程中的线程也可以并发执行

独立性

同一进程中的多个线程独立性比不同进程间的独立性差很多。 每个进程都是独立的地址空间和资源,同一进程下多线程他们共享进程下的资源,而且通常他们往往是用来相互合作的,每个线程都可以访问所在进程的所有地址空间,比如一个线程打开的文件,可以被其他线程读写。

调度性

传统OS,进程作为资源分配和调度分派的基本单位,进程是可以独立运行的基本单位,不过进程调度切换时空开销大 引入线程的OS,线程是运行调度和分派的基本单位,线程才是独立运行的基本单位,线程切换时,仅仅需要保存和设置少量寄存器内容,代价远远小于进程切换,不过需要注意是同一个进程内线程切换不会进程切换,但是不同进程中的线程进程切换,仍旧会导致进程切换。

拥有资源

进程拥有资源,并且作为系统中拥有资源的独立基本单位。 线程自身不拥有系统资源,仅仅拥有一点必不可少的,独立运行需要的资源,比如线程中的TCB。 除了自身的丁点儿资源外,共享所属进程的资源,同一个进程下所有线程,拥有相同的地址空间。

多处理器支持

传统进程(或者说单线程进程)只能运行于一个处理机上,不管有多少个处理机; 但是对于多线程进程,就可以将一个进程中的多个线程分配到多个处理机上,并行运行 简言之,多线程可以让多核CPU充分发挥性能并行运行。

系统开销

进程和线程的创建撤销,系统都要为止分配和回收资源,比如内存空间、IO设备等,进程和线程的上下文切换,系统也都需要付出一定的时空开销。 但是,线程相关的开销明显小于进程。

线程简介

各线程之间也是存在资源共享和相互合作的,线程在运行时也是间断的,轮转切换的。 线程也是有运行状态的,这一点与进程并没有本质区别,最主要的状态也是就绪、执行、阻塞 进程的控制核心信息保存在PCB中,线程也有对应的组成---TCB,所有用于控制和管理线程的信息都保存在TCB中 image.png 线程尽管是另外一种完全不同的事物,但是毕竟是从进程的概念演化而来,也是操作系统对程序运行抽象的一部分,所以,线程必然与进程有着很多的相似点

线程实现

线程的实现主要有三种形式

  • 内核支持
  • 用户级线程
  • 另外就是二者的组合

897393-20190207203231676-260615211.png 从上面的分析中可以看得出来,内核支持和用户级都有各自明显的缺点和优点。

有些操作系统把用户级线程和内核支持线程两种方式进行组合,提供了组合方式ULT/KST 线程。

在组合方式线程系统中, 内核支持多KST线程的建立、调度和管理 同时,也允许用户应用程序建立、调度和管理用户级线程。

一些内核支持线程对应多个用户级线程,程序员可按应用需要和机器配置对内核支持线程数目进行调整,以达到较好的效果。 组合方式线程中,同一个进程内的多个线程可以同时在多处理器上并行执行,而且在阻塞一个线程时,并不需要将整个进程阻塞。 所以,组合方式多线程机制能够结合 KST和 ULT两者的优点,并克服了其各自的不足。 本文作者:程序员潇然 疯狂的字节X https://crazybytex.com/

线程的同步与通信

关于进程的同步与通信的相关逻辑原理,对于进程的同步与通信绝大多数都是适用的。 针对于这些原理,多线程OS也提供了多种同步机制,如互斥锁、条件变量、计数信号量以及多读、单写锁等。

信号量机制

进程中的信号量机制完全适合多线程同步 根据用法分为两种

  • 私用信号量(private samephore)
  • 公用信号量(public semaphort)

系统运行中,有多个进程,进程中又有多个线程。 如果是为了同一进程中多个线程同步设置的信号量,量属于特定的进程所有,这就叫做私用,OS并不知道私用信号量的存在。 如果是为了不同进程或者不同进程中的线程之间而设置的,就叫做公用。其数据结构是存放在受保护的系统存储区中,由OS为它分配空间并进行管理,故也称为系统信号量。

互斥锁(mutex)

互斥锁是一种比较简单的、用于实现线程间对资源互斥访问的机制 互斥锁可以有两种状态

  • 开锁(unlock)
  • 关锁(lock)

当一个线程需要读/写一个共享数据段时,需要对mutex进行上锁,离开时需要解锁。

上锁时,首先校验 mutex 的状态,如果它已处于关锁状态,则试图访问该数据段的线程将被阻塞;如果 mutex处于开锁状态,则将 mutex 上锁后便去读/写该数据段。

线程完成操作后,必须将 mutex 解锁,同时还需要将阻塞在该互斥锁上的一个线程唤醒,其它的线程仍被阻塞在等待mutex打开的队列上。

另外,为了减少线程被阻塞的机会,在有的系统中还提供了一种用于 mutex 上的操作命令 Trylock。 顾名思义,并不会因为无法进入而阻塞,若 mutex 处于上锁状态,则 Trylock 并不会阻塞该线程,而只是返回一个指示操作失败的状态码。

条件变量

在许多情况下,只利用 mutex 来实现互斥访问可能会引起死锁 比如A线程请求资源顺序为R1,R2,B线程请求资源顺序为R2,R1 如果A对mutex 1上锁成功进入临界区后,需要获取R2的锁mutex 2,可是此时B获得了资源R2,对mutex 2已经上锁,此时,A等待mutex 2 B等待mutex 1,形成了死锁

所以说,锁,应该是仅仅用于在条件成立时进行操作时的一个同步保障,而不能在整个过程中都依靠锁 可以借助于条件变量,就是条件

每一个条件变量通常都与一个互斥锁一起使用,单纯的互斥锁用于短期锁定,主要是用来保证对临界区的互斥进入。 而条件变量则用于线程的长期等待,直至所等待的资源成为可用的资源。

申请

Lock mutex
while (条件状态不满足) {
wait(condition variable);//释放锁,线程挂起等待,直到条件满足通知;
}
临界区其他操作
unlock mutex;

释放

Lock mutex
一些操作
unlock mutex;
wakeup(condition variable);

简言之,借助于条件变量用于控制长时间的等待,锁用于控制对资源的同步。

总结

本文对线程进行了非常简单的介绍,线程之于进程在很多的方面有着极其类似的逻辑,尤其是从调度的视角看。

毕竟线程就是对进程中关于调度部分的独立抽象。

只要能够理解进程和线程的目的就能够很好地理解他们相似的原因,因为都是操作系统对于程序运行的抽象描述,线程是进程的更加细粒度的掌控。

在换句话说就是操作系统的角度对程序的执行抽象为:“资源的分配”“调度 ” 最初这两个概念都是加诸于进程这个概念上,后续为了更加高效将两个概念进行了拆分,就是这样

所以说,对于原先介绍的进程的相关概念中关于调度部分的绝大多数理论,都是适用于线程概念的 common_log.png 转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-60-1-1.html

关注下面的标签,发现更多相似文章

文章被以下专栏收录:

    黄小斜学Java

    疯狂的字节X

  • 目前专注于分享Java领域干货,公众号同步更新。原创以及收集整理,把最好的留下。
    包括但不限于JVM、计算机科学、算法、数据库、分布式、Spring全家桶、微服务、高并发、Docker容器、ELK、大数据等相关知识,一起进步,一起成长。
热门推荐
[若依]微服务springcloud版新建增添加一个
[md]若依框架是一个比较出名的后台管理系统,有多个不同版本。
[CXX1300] CMake '3.18.1' was not
[md][CXX1300] CMake '3.18.1' was not found in SDK, PATH, or
java 解析modbus 协议 Modbus4j应用 使用mo
[md]本文记录使用java开发modbus协议程序,与串口进行连接,使用