文章目录
前言
本文将详细介绍【线程】相关内容,包括,线程的结构、状态、调度等
一、线程
1.线程的基本结构
线程主要由线程 ID、程序计数器、寄存器集合和栈组成。
1.1线程 ID
线程ID是线程的唯一标识符,操作系统通过线程 ID 来区分不同的线程,可以通过线程 ID 来跟踪特定线程的执行情况。
1.2程序计数器
记录线程当前执行的指令位置。由于线程是可以暂停和恢复执行的,程序计数器可以保证线程在暂停后能够从正确的位置继续执行。
如:一个线程在执行一个包含多个循环的函数时被中断,当它再次获得执行权时,程序计数器会指示它从上次中断的循环位置继续执行。
1.3寄存器集合
用于存储线程执行过程中的临时数据,如操作数、计算结果等。这些寄存器可以加快线程的运算速度,因为数据存储在寄存器中比存储在内存中访问速度更快。不同的 CPU 架构有不同数量和类型的寄存器,线程会根据需要使用这些寄存器。
1.4栈
每个线程都有自己的栈空间,用于存储局部变量、函数调用信息等。当一个函数被调用时,函数的参数、局部变量和返回地址等信息都会被压入栈中。
2.线程的状态
2.1新建状态new
当通过编程语言提供的线程创建方法(如 Java 中的Thread类的构造函数)创建一个线程后,线程就处于新建状态。此时,线程只是一个对象,还没有开始执行,就像一个刚刚被制造出来还没有启动的机器。
2.2就绪状态runnable
当线程对象调用start()方法后,线程就进入就绪状态。处于就绪状态的线程已经具备了运行的条件,等待 CPU 分配时间片来运行。可以把它想象成运动员已经在起跑线上做好了准备,就等裁判发令(CPU 分配时间片)。
2.3运行状态running
当线程获得 CPU 时间片后,就进入运行状态,开始执行线程中的代码。在运行过程中,线程可能会因为时间片用完或者被更高优先级的线程抢占 CPU 而暂停运行。
如:在一个多任务操作系统中,多个线程会竞争 CPU 时间片,一个线程可能在运行了一小段时间后,时间片用完,就会暂停运行进入blocked状态,让其他线程运行。
2.4阻塞状态blocked
线程在运行过程中可能会因为等待某些事件而进入阻塞状态。
如:当一个线程需要读取一个尚未准备好的数据时,它会暂停执行,进入阻塞状态,等待数据可用。
常见的导致线程阻塞的情况包括等待 I/O 操作完成(如读取文件、网络通信等)、等待获取锁(用于同步多个线程对共享资源的访问)等。
2.5死亡状态dead
当线程执行完了它的任务或者因为出现异常等原因提前结束时,线程就进入死亡状态。处于死亡状态的线程不再占用 CPU 资源,也不能再被重新启动。例如,一个线程的任务是计算从 1 加到 100,当它完成这个计算后,就会进入死亡状态。
3.线程的同步与互斥
3.1同步
同步是指多个线程在访问共享资源时,通过一定的机制来协调它们的执行顺序,以确保共享资源的正确使用。
如:在一个银行账户管理系统中,有两个线程,一个线程负责存款操作,另一个线程负责取款操作。如果没有同步机制,可能会出现取款线程在存款线程还没有更新账户余额之前就读取了旧的余额信息,导致数据错误。常见的同步机制包括信号量、条件变量等。
3.2互斥
互斥是一种特殊的同步,主要是为了防止多个线程同时访问共享资源。互斥通常通过互斥锁来实现。
如:在一个多线程的文件写入系统中,为了防止多个线程同时写入同一个文件而导致文件内容混乱,会使用互斥锁。当一个线程需要写入文件时,它首先获取互斥锁,独占文件的写入权,其他线程在这个线程释放互斥锁之前无法获取写入权。
4.线程的调度
线程调度是指操作系统决定哪个线程可以获得 CPU 时间片并运行的过程。
4.1抢占式调度
在这种调度方式下,操作系统可以在任何时候中断正在运行的线程,并将 CPU 分配给其他线程。这种调度方式的优点是可以保证高优先级的线程能够及时获得 CPU 资源,但是也可能导致低优先级的线程长时间得不到运行。
如:在一个实时操作系统中,高优先级的任务(如紧急的安全监控任务)可以抢占低优先级的任务(如常规的数据备份任务)的 CPU 时间片。
4.2非抢占式调度
在这种调度方式下,一个线程会一直运行,直到它主动放弃 CPU(如因为等待某个事件或者执行完毕)。这种调度方式相对简单,但是可能会导致某些线程长时间占用 CPU,而其他线程等待时间过长。