线程的基础
概要
1.操作系统发展史
2.进程的诞生
3.线程的诞生
4.一个故事做总结
第1节 操作系统发展史
在计算机刚出现的时候,是为了解决数学计算的问题,因为很多大量的计算通过人力去完成是很耗时间和人力成本的。
在最初的时候,计算机只能接受一些特定的指令,用户输入一个指令,计算机就做一个操作。当用户在思考或者输入数据时,计算机就在等待。显然这样效率和很低下,因为很多时候,计算机处于等待用户输入的状态。
批处理操作系统诞生
把一系列需要操作的指令预先写下来,形成一个清单,然后一次性交给计算机,计算机不断地去读取指令来进行相应的操作。用户可以将需要执行的多个程序写在磁带上,然后交由计算机去读取并逐个地执行这些程序,并将输出结果写到另一个磁带上。
批处理操作系统的缺点
假如有两个任务A和B,任务A在执行到一半的过程中,需要读取大量的数据输入(I/O操作,很耗时),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源。
第2节 进程的诞生
人们想能否在任务A读取数据的过程中,让任务B去执行,当任务A读取完数据之后,让任务B暂停,然后让任务A继续执行?那么问题来了—— 原来每次都是一个程序在计算机里面运行,也就说内存中始终只有一个程序的运行数据。如果想要任务A在执行I/O操作的时候,让任务B去执行,必然内存中要装入多个程序,那么如何处理呢?多个程序使用的数据如何进行辨别呢?并且当一个程序运行暂停后,后面如何恢复到它之前执行的状态呢?
进程的诞生
人们发明了进程,用进程来对应一个程序,每个进程对应一定的内存地址空间,并且只能使用它自己的内存空间,各个进程间互不干扰。并且进程保存了程序每个时刻的运行状态,这样就为进程切换提供了可能。当进程暂时时,它会保存当前进程的状态(比如进程标识、进程的使用的资源等),在下一次重新切换回来时,便根据之前保存的状态进行恢复,然后继续执行。
进程的缺点
一个进程在一个时间段内只能做一件事情,如果一个进程有多个子任务,只能逐个地去执行这些子任务。
对于一个电商系统而言,它不仅要把图像数据显示在画面上,还要与服务端进行通信获取商品数据,还要处理用户的交互操作。如果一个进程中,每次只能执行一个任务,对于电商系统而言,用户可能需要一直等待,直到所有的操作在单个进程中处理完。显然,这样的系统,显示是无法满足用户的需求的。
第3节 线程的诞生
可不可以将进程中这些子任务分开执行呢?即在系统获取商品数据的同时,如果用户点击了某个按钮,则会暂停获取图像数据,而先去响应用户的操作(因为用户的操作往往执行时间很短),在处理完用户操作之后,再继续获取商品数据。于是人们发明了线程。
线程的诞生
让一个线程去执行一个子任务,这样一个进程就包括了多个线程,每个线程负责一个独立的子任务,这样在用户点击按钮的时候,就可以暂停获取商品数据的线程,让图像线程响应用户的操作,响应完之后再切换回来,让获取图像的线程得到CPU资源。从而让用户感觉系统是同时在做多件事情的,满足了用户对实时性的要求。
简单的说
——进程让操作系统的并发性成为可能。
——线程让进程的内部并发成为可能。
【注意】
第4节 一个故事做总结
计算机的核心就是CPU,所有的计算都在CPU中进行处理。CPU像是一个工厂,时刻运行着。
假定工厂的电力有限,一次只能供给一个车间使用。进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
一个车间里,可以有很多工人。他们协同完成一个任务。
线程就好比车间里的工人。一个进程可以包括多个线程。
车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。
当这个房间里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
一个防止他人进入厕所的简单方法,就是门口加一把锁。
先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
还有些房间,可以同时容纳n个人,比如餐厅或者茶水间。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。
这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。不难看出,锁是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为锁较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许每个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。