线程惯性

科技工作者之家 2020-11-17

线程惯性指在多线程编程中的一种错误的心理状态,它假定当前编写的代码执行完毕后会继续执行下一条代码。而实际上,在现代处理器中,线程随时(当该线程的时间片用完时)可能被处理器冻结,而处理器被另一线程抢占(这里指单处理器上的情况,在多处理器上,情况更加复杂)。

定义线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

线程惯性是指以单线程代码执行方式来分析多线程代码。在多线程编程中,代码是并发、并行并且是异步执行的,与代码顺序执行相反。因此,如果程序执行的结果依赖于这两个(或者可能更多)线程的顺序,程序就可能出错。因为线程执行具有不确定性,这种错误并不是每次都会出现,而且在某些特定的机器上可能永远不会出现。因此,这种错误较难发现。在实际编程中,一般采用线程安全方法来解决线程惯性问题。

线程安全线程安全是编程中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。一般来说,线程安全的函数应该为每个调用它的线程分配专门的空间,来储存需要单独保存的状态(如果需要的话),不依赖于“线程惯性”,把多个线程共享的变量正确对待(如,通知编译器该变量为“易失(volatile)”型,阻止其进行一些不恰当的优化),而且,线程安全的函数一般不应该修改全局对象。很多C库代码(比如某些strtok的实现,它将“多次调用中需要保持不变的状态”储存在静态变量中,导致不恰当的共享)不是线程安全的,在多线程环境中调用这些函数时,要进行特别的预防措施,或者寻找别的替代方案。以Java编程语言为例,编程的方法越来越高效和完善。针对线程安全问题,从Java2中非线程安全的 Hash Map 到后来提出了线程安全的 Hashtable 和Concurrent Hash Map,再到 Java8 的普及和应用又为线程安全问题提出了新的解决办法。Java8 中新增了Lambda表达式、流和默认方法。提出了行为参数化的软件开发模式。同时在 Lambda 表达式的基础上提出了流处理。对于流处理这种较为新型的处理数据模式,由于流处理避免了多线程程序的线程临界域访问带来的非线程安全问题,为程序开发者性能提高提供了新思路1。

多线程编程多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。

软件多线程。即便处理器只能运行一个线程,操作系统也可以通过快速的在不同线程之间进行切换,由于时间间隔很小,来给用户造成一种多个线程同时运行的假象。这样的程序运行机制被称为软件多线程。如微软的Windows作业系统和Linux就是在各个不同的执行绪间来回切换,被称为单人多任务作业系统。而DOS这类文字接口作业系统在一个时间只能处理一项工作,被视为单人单工作业系统。

在多线程编程模型中,线程间是相互独立而又相互依赖的。使用多线程编程模型编程就是将进程的任务划分为执行的线程,每一个线程为一个顺序的单控制流,而所有线程都是并发、并行并且是异步执行的,这样,多线程编程模型具有实现进程并行计算、节省内存空间、减少系统管理开销、快速切换、(线程)通信易于实现等优点。多线程编程模型提供了一种新型的模块化编程思想和方法,这种方法能清晰地表达各种独立事件的相互关系,但是这种多线程编程模型的并发和异步优点也带来了一定的复杂度:并发和异机制带来了线程间资源竞争无序性。因此需要引入同步机制来消除这种复杂度和实现线程间共享数据,以一致的顺序执行一组操作。多线程编程提供一种新型的模块化思维方式和编程方式,它将独立的或者低耦合的执行代码显式地分离,并将这些低耦合的执行代码设计为相对独立运行的线程,这种相对独立运行的线程必须相互依赖和相互合作才能提供一套完善而又完整的接口、服务或系统,在此总结和介绍流水线模型、对等工作组模型、客户端/服务器模型、主从架构模型和其它模型等5种常见多线程编程模型2。

本词条内容贡献者为:

王慧维 - 副研究员 - 西南大学

科技工作者之家

科技工作者之家APP是专注科技人才,知识分享与人才交流的服务平台。