操作系统中线程 ID 和线程句柄的区别

2025年5月1日 | 7 分钟阅读

引言

现代计算系统将线程视为操作系统可调度和运行的最小执行单元。进程或线程内的并发执行取代了顺序执行,有助于优化CPU利用率和应用程序的响应能力。

现在,在处理线程时,我们经常听到两个概念:线程ID线程句柄。虽然它们都与线程管理有关,但它们的作用不同,在线程操作中具有专门的用途。在本文中,我们将学习线程ID和线程句柄的区别,它们在操作系统中的实际用法,以及它们的功能。

但在应用线程ID和线程句柄的这些概念之前,我们需要了解什么是线程及其在操作系统中的作用。

什么是线程?

线程是可调度的程序指令的最小长度。单个进程下存在多个线程,这些线程属于某个特定进程。因此,它们共享内存、文件和全局变量。线程通常用于

  • 高效的资源利用:允许并发操作,从而最大限度地利用CPU
  • 响应能力:使您的用户界面在后台工作时保持响应。
  • 多任务处理:在应用程序中同时执行多项任务。

线程执行上下文围绕父进程的资源、内存和堆栈构建,与其它线程共享运行时,但拥有自己的程序计数器、堆栈以及其他线程特定的存储。

什么是线程ID?

线程ID是进程中线程的唯一标识符。它是一个整数值,用于区分一个线程与另一个线程。操作系统通常在创建线程时分配线程ID。这提供了一种在进程内引用和识别特定线程的方法。线程ID可能有助于调试、日志记录或监控单个线程的行为。但它不能直接用于控制它;它只能用于识别。

线程ID的用途

  • 线程识别:线程ID在系统或进程中的多个线程中识别一个特定线程。
  • 线程管理:它为开发人员和系统工具提供了一种监控、跟踪和查询线程的方法。
  • 调试和日志记录:在程序行为调试期间,线程ID通常用于区分不同的线程。
  • 线程特定操作:某些系统调用和函数需要线程ID来进行信号发送、取消或更改优先级。

线程ID的作用域

线程ID的范围因操作系统而异。例如

  • 全局作用域:在某些操作系统(如Windows)中,线程ID在整个系统都是唯一的。
  • 局部作用域:线程ID可能只需要在进程内是唯一的。例如,如果您的系统是运行POSIX线程的Linux系统,那么线程ID可能只在该一个进程内是唯一的。

线程ID的特性

  • 唯一性:在大多数系统中,每个线程都有一个唯一的线程ID,以便在整个系统范围内无冲突地标识线程。对于某些操作系统,它可能只在单个进程内是唯一的。
  • 生命周期内不可变:创建后的ID在线程生命周期内保持不变。然后,当线程终止时,操作系统可能会回收该ID并将其分配给新线程。
  • 系统分配:创建线程时,操作系统会为其生成并分配一个线程ID。

线程ID的使用示例

  • 调试工具:当调试工具决定显示给定进程的活动线程时,它通常使用线程ID。
  • 日志消息:开发人员将线程ID添加到日志消息中是很常见的,这样他们就可以知道是哪个线程导致了特定的日志条目。
  • 向特定线程发送信号:在Linux中,pthread_self()函数只是获取调用线程的ID。在Windows中,GetCurrentThreadId()函数返回当前线程的ID。

什么是线程句柄?

操作系统提供了一个名为线程句柄或线程对象的数据结构,用于操作和控制线程。在多线程编程中,线程句柄是一个非常重要的工具,它允许通过API与系统中的线程进行交互。常见操作包括暂停、恢复、等待线程终止或终止线程。创建线程时获得的句柄可用于引用底层线程。它是程序与线程通信并执行线程操作的方式。

线程句柄的用途

线程句柄是应用程序用来与线程交互并为其执行不同操作的接口。这些包括

  • 同步:在Windows中,线程用于同步操作,例如使用WaitForSingleObject()函数等待线程完成执行。
  • 线程控制:应用程序能够控制线程的执行。例如,它们可以通过平台特定的函数暂停或恢复线程。
  • 查询线程信息:句柄提供查询或更改线程属性的功能,例如优先级或处理器亲和性。
  • 安全资源管理:CloseHandle()等函数关闭句柄,并确保OS资源得到妥善清理。
  • 线程终止:如果需要终止线程,可以使用句柄。例如,Windows中的TerminateThread()函数需要一个线程句柄。

线程句柄的作用域

通常,线程句柄仅在创建线程的进程中有效。除非显式共享,否则它不能跨进程使用。

线程句柄的特性

  • 进程本地:线程句柄通常仅在其创建的进程内有效。它不能直接跨进程传递或使用,但如果操作系统设计允许,则可以。
  • 系统特定表示:每个操作系统对线程句柄的表示方式不同。
  • 不全局唯一:与线程ID不同,线程句柄在系统中不是唯一的。一个或多个句柄指向同一进程中的同一线程对象是可能的或常见的。
  • 资源支持:线程句柄代表操作系统资源。对于句柄,OS会分配内存和跟踪结构。您需要显式关闭它,否则会造成资源泄漏。

线程句柄的生命周期

  • 句柄的有效性取决于应用程序的管理。句柄可以在应用程序显式关闭之前一直使用。关闭句柄意味着它不再需要,并且OS通常会提供一个函数来执行此操作。

线程句柄的使用示例

  • Windows中的CreateThread()函数返回新创建线程的句柄,该句柄可与WaitForSingleObject()和TerminateThread()函数一起使用。在Windows中,线程句柄是HANDLE类型,是指向内核中线程对象的不可变指针。
  • 在Linux的POSIX线程模型中,pthread_t对象起线程句柄的作用。

线程ID和线程句柄的区别

方面线程 ID线程句柄
目的我们主要使用它来识别线程并查询其信息。它用于对线程执行操作,如同步、暂停或终止。
性质和表示一个数字或系统定义的,唯一标识线程的值。一个系统特定的引用,用于在管理方面标识线程。
生命周期ID在线程生命周期内有效。通常,在线程终止后,OS会对其进行重用。它由应用程序显式关闭时关闭。
唯一性在系统(或进程,取决于OS)中是唯一的(或在进程内是唯一的)。不一定在系统中唯一。句柄与它们所属的进程绑定。
系统交互它不能直接用于操作线程。它更多地是作为标识的引用。可以使用OS特定的API来控制线程的状态。
范围它可能具有全局作用域(在系统中唯一)或局部作用域(仅在进程中唯一)。仅在创建线程的进程内有效。

线程ID和线程句柄的用例

  1. 何时使用线程ID
    • 线程间通信:ID可用于引用其他线程以便相互通信。
    • 线程识别:查找特定线程的信息以进行查询。
    • 调试:许多调试工具使用线程ID,日志会使用线程ID跟踪线程活动。
  2. 何时使用线程句柄
    • 资源管理:由于需要通过句柄妥善管理线程资源,因此最好确保它们可用。
    • 线程控制:它用于执行诸如暂停、恢复或终止线程等操作系统操作。
    • 同步:例如,线程通过使用同步原语(如WaitForSingleObject() (Windows))等待另一个线程完成执行。

结论

线程在没有线程ID和线程句柄的情况下很难独立运行。处理多线程应用程序的开发人员应该了解它们在句柄上的差异以及这些句柄的用例。线程ID用于标识和查询,而线程句柄用于管理和控制线程。利用这些工具,开发人员可以编写高效、健壮、可维护的多线程程序。