windows线程基础

Windows线程机制详解

线程的基本概念

在Windows操作系统中,线程是程序执行的最小单位。每个进程至少包含一个线程(主线程),但可以创建多个线程来并行执行任务。线程与进程的主要区别在于:

  1. 资源分配:进程拥有独立的地址空间和系统资源,而线程共享进程的资源
  2. 调度单位:线程是CPU调度的基本单位,进程只是资源的容器
  3. 创建开销:创建线程比创建进程的开销小得多

Windows线程由以下几个核心部分组成:

  1. 线程内核对象:操作系统用来管理线程的数据结构,包含线程状态、优先级等信息
  2. 线程环境块(TEB):包含线程特有的数据,如异常处理链、线程本地存储等
  3. 用户模式栈:用于存储函数调用、局部变量等
  4. 内核模式栈:当线程调用系统服务时使用

线程的创建与终止

创建线程

在Windows中创建线程主要有两种方式:

  1. 使用CreateThread API
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性,通常为NULLSIZE_T dwStackSize,                      // 栈大小,0表示使用默认大小LPTHREAD_START_ROUTINE lpStartAddress,   // 线程函数地址LPVOID lpParameter,                      // 传递给线程函数的参数DWORD dwCreationFlags,                   // 创建标志,如CREATE_SUSPENDEDLPDWORD lpThreadId                       // 接收线程ID
);
  1. 使用C运行时库的_beginthreadex
uintptr_t _beginthreadex(void *security,             // 安全属性unsigned stack_size,        // 栈大小unsigned (__stdcall *start_address)(void *), // 线程函数void *arglist,              // 参数unsigned initflag,          // 初始状态unsigned *thrdaddr          // 线程ID
);

重要说明

  • 如果使用C/C++运行时库,建议使用_beginthreadex而非CreateThread,因为前者会正确初始化线程特定的C运行时库数据
  • 线程函数必须返回DWORD并接受LPVOID参数
  • 创建线程后必须调用CloseHandle关闭线程句柄,否则会造成资源泄漏

线程终止

线程可以通过以下方式终止:

  1. 正常返回:线程函数执行return语句
  2. 调用ExitThread:立即终止当前线程
  3. 被其他线程终止:使用TerminateThread(不推荐)

最佳实践

  • 应尽量避免使用TerminateThread,因为它不会给线程清理资源的机会
  • 线程应通过返回或调用ExitThread来正常终止
  • 主线程退出会导致整个进程终止,包括所有其他线程

线程调度与优先级

Windows使用基于优先级的抢占式调度算法。每个线程都有一个优先级,范围从0(最低)到31(最高)。

线程优先级级别

Windows线程优先级分为以下几个大类:

  1. 空闲优先级(0-6):用于后台任务
  2. 普通优先级(7-15):大多数应用程序线程的默认级别
  3. 高优先级(16-22):用于时间关键任务
  4. 实时优先级(23-31):用于系统关键任务

可以通过以下API设置线程优先级:

BOOL SetThreadPriority(HANDLE hThread, int nPriority);
BOOL SetThreadPriorityBoost(HANDLE hThread, BOOL bDisablePriorityBoost);

时间片分配

Windows调度器为每个线程分配一个时间片(通常为20-30ms)。当时间片用完或更高优先级线程就绪时,当前线程会被抢占。

调度要点

  1. 高优先级线程总是先于低优先级线程执行
  2. 相同优先级的线程按时间片轮转
  3. 前台进程的线程会获得稍长的时间片
  4. 系统会动态提升交互式线程的优先级

线程同步机制

多线程编程中最关键的问题是如何安全地访问共享资源。Windows提供了多种同步机制:

1. 临界区(Critical Section)

CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);EnterCriticalSection(&cs);
// 访问共享资源
LeaveCriticalSection(&cs);DeleteCriticalSection(&cs);

特点

  • 只能用于同一进程内的线程同步
  • 效率高,不进入内核模式(在没有竞争时)
  • 不支持超时等待

2. 互斥量(Mutex)

HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);WaitForSingleObject(hMutex, INFINITE);
// 访问共享资源
ReleaseMutex(hMutex);CloseHandle(hMutex);

特点

  • 可以跨进程使用
  • 支持超时等待
  • 比临界区开销大

3. 事件(Event)

HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);// 线程1
SetEvent(hEvent);// 线程2
WaitForSingleObject(hEvent, INFINITE);

特点

  • 可用于线程间通知
  • 有手动重置和自动重置两种类型
  • 支持跨进程使用

4. 信号量(Semaphore)

HANDLE hSem = CreateSemaphore(NULL, initialCount, maximumCount, NULL);WaitForSingleObject(hSem, INFINITE);
// 访问受保护资源
ReleaseSemaphore(hSem, 1, NULL);CloseHandle(hSem);

特点

  • 控制对有限数量资源的访问
  • 支持计数
  • 可以跨进程使用

线程局部存储

线程局部存储(TLS)允许每个线程拥有变量的独立副本。Windows提供两种TLS实现:

1. 动态TLS

DWORD tlsIndex = TlsAlloc();  // 分配TLS索引// 设置线程特定值
TlsSetValue(tlsIndex, pData);// 获取线程特定值
void* pData = TlsGetValue(tlsIndex);TlsFree(tlsIndex);  // 释放TLS索引

2. 静态TLS

__declspec(thread) int tlsVar = 0;

比较

  • 动态TLS更灵活,但访问速度稍慢
  • 静态TLS效率更高,但数量有限(约1000个)
  • 静态TLS在DLL中使用时需要注意初始化问题

线程池

创建和销毁线程的开销较大,Windows提供了线程池机制来优化:

工作项提交

TP_WORK* pWork = CreateThreadpoolWork(WorkCallback, pContext, NULL);
SubmitThreadpoolWork(pWork);
WaitForThreadpoolWorkCallbacks(pWork, FALSE);
CloseThreadpoolWork(pWork);

定时任务

TP_TIMER* pTimer = CreateThreadpoolTimer(TimerCallback, pContext, NULL);
// 设置2秒后执行,之后每1秒重复
ULARGE_INTEGER ulDueTime;
ulDueTime.QuadPart = -20000000LL;  // 2秒
SetThreadpoolTimer(pTimer, (PFILETIME)&ulDueTime, 1000, 0);

优势

  • 自动管理线程数量
  • 减少线程创建销毁开销
  • 内置负载均衡

常见问题与调试

线程死锁

死锁通常发生在多个线程互相等待对方持有的锁时。预防死锁的方法包括:

  1. 按固定顺序获取锁
  2. 使用超时机制
  3. 避免嵌套锁

调试技巧

  1. WinDbg命令
~*kv         // 查看所有线程调用栈
!locks       // 查看临界区状态
  1. Visual Studio调试
  • 使用"并行堆栈"窗口查看线程关系
  • 设置数据断点监视共享变量

性能优化建议

  1. 线程数量

    • CPU密集型任务:线程数≈CPU核心数
    • IO密集型任务:可适当增加线程数
  2. 避免过度同步

    • 缩小临界区范围
    • 使用无锁数据结构
  3. 线程亲和性

SetThreadAffinityMask(hThread, affinityMask);

可以减少CPU缓存失效,提高性能

总结

Windows线程机制提供了强大的并发编程能力,但也带来了复杂性。理解线程的基本原理、掌握同步机制、合理使用线程池是编写高效、稳定多线程程序的关键。在实际开发中,应特别注意资源同步和线程安全,避免竞态条件和死锁等问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92246.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92246.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Numpy科学计算与数据分析:Numpy随机数生成入门

Numpy随机数生成实战 学习目标 通过本课程,学员将掌握如何使用Numpy库生成不同类型的随机数,包括随机整数、随机浮点数以及从特定分布中抽样的方法。本课程将通过理论讲解与实践操作相结合的方式,帮助学员深入理解Numpy在随机数生成方面的强…

使用 C# 通过 .NET 框架开发应用程序的安装与环境配置

文章目录1. .NET介绍2. IDE2.1 Rider 安装2.2 Visual Studio 安装3. SDK安装与环境配置3.1 单独下载安装 .NET SDK3.2 Visual Studio 工作负荷安装SDK4. 相关问题4.1 我以前使用 Unity 写 C# 脚本不需要额外的编译器,为什么现在需要?1. .NET介绍 .NET 是…

Scikit-learn - 机器学习库初步了解

目录1. 主要算法分类1.1 监督学习 (Supervised Learning)1.2 非监督学习 (Unsupervised Learning)1.3 半监督学习 (Semi-Supervised Learning)1.4 强化学习 (Reinforcement Learning)1.5 遗传算法 (Genetic Algorithm)2. 选择合适的机器学习模型2.1 分类 (Classification)2.2 回…

关于 idea 里 properties 文件的中文乱码问题

背景 你会发现 properties 文件里的中文可能会出现乱码。 这个因为 properties 规范是使用 iso-8859-1 存储的,不支持中文(也不支持西欧里法语、德语里奇怪的字母) properties 的标准制定于很早,所以没考虑这么多,prop…

BVH文件 解析 解读的python第三方类库 推荐

我们面临多个第三方库选项用于解析BVH文件,根据您的列表,我将分析几个关键库的特点,并推荐最适合当前任务的库。我们将基于以下标准进行选择: ​​功能性​​:是否能准确解析关节角度数据,支持关键帧操作 ​…

uni-app X能成为下一个Flutter吗?

哈喽,我是老刘 老刘使用Flutter作为客户端主要技术栈的这六七年的时间里,关于跨平台开发的争议和新技术始终没有停过。 “一套代码,多端运行”——这个让无数开发者心动的承诺,究竟是技术革命还是美丽的谎言? 想象一…

Spring Cloud Gateway全栈实践:动态路由能力与WebFlux深度整合

一、为什么需要下一代网关? 传统网关的三大瓶颈: #mermaid-svg-Kdei9Io6KntYGQc4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Kdei9Io6KntYGQc4 .error-icon{fill:#552222;}#mermaid-svg-…

MongoDB数据存储界的瑞士军刀:cpolar内网穿透实验室第513号挑战

软件名称:MongoDB 操作系统支持:Linux、Windows、macOS(Docker版全平台通用!) 软件介绍: MongoDB是一个基于分布式架构的NoSQL数据库,擅长处理复杂数据类型(如嵌套对象、数组&…

SPI TFT全彩屏幕驱动开发及调试

简介SPI(Serial Peripheral Interface)是一种广泛使用的串行通信协议,常用于微控制器(MCU)与外围设备(如传感器、显示屏、存储器等)之间的通信。SPI具有全双工传输、主从结构和较高的传输速率&a…

Linux学习—数据结构(链表2)

1.单向链表6.链表的查找在链表中找到指定的第一个元素沿用遍历思想,每次访问一个节点元素判断是否为要找的节点符合条件返回该节点地址到最后没有找到符号条件的节NULLlinknode *find_linklist(linknode *phead, datatype tmpdata) {linknode *ptmpnode NULL;ptmpn…

MySQL 备份利器 Xtrabackup 全解析:从部署到恢复的实战指南

数据库备份恢复是 DBA 的 “保命” 技能,生产业务不仅要保证有合适的备份策略,也要定期验证备份的有效性和恢复演练流程,因为数据恢复和验证可能会涉及多方合作,演练可以让灾难真正发生时,多方配合有条不紊的将数据恢复…

EAGLE-2:通过动态草稿树加速语言模型推理

温馨提示: 本篇文章已同步至"AI专题精讲" EAGLE-2:通过动态草稿树加速语言模型推理 摘要 现代 Large Language Models(LLMs)的推理过程既昂贵又耗时,而 speculative sampling 已被证明是一种有效的解决方案…

防水防尘防摔性能很好的智能三防手机,还有22000mAh大电池

在电力巡检的崇山峻岭间,在野外地质勘探的风沙深处,在应急救援的急风骤雨里,传统智能设备因其固有的脆弱性与续航短板往往力不从心,甚至成为保障工作连续性的掣肘。而真正的智能三防手机应是一堵移动的堡垒,集坚不可摧…

Charles中文版抓包工具使用指南 提高API调试和网络优化效率

在现代开发过程中,调试API、捕获HTTP/HTTPS流量和优化应用的网络性能已经成为开发者的常见任务。尤其是在调试复杂的API接口和分析网络请求时,开发者需要一款高效且功能强大的工具。Charles抓包工具凭借其强大的网络调试功能和易用的操作界面&#xff0c…

【C#补全计划:类和对象(九)】接口

一、接口的概念1. 概念:接口是行为的抽象规范,也是一种自定义类型2. 接口声明规范:(1)不包含成员变量(2)只包含属性、方法、索引器、事件(3)成员不能被实现(4…

SRS简介及简单demo

SRS介绍 SRS(Simple Realtimes Server)是一款开源的实时流媒体服务器,专注于解决直播、实时互动等场景的流媒体传输问题。SRS 的设计目标是 “简单、稳定、高效”,专门针对实时流媒体协议(如 RTMP、HLS、HTTP-FLV、WebRTC 等)进行优化,专注于解决 “低延迟、高并发” 的…

python基础:数据解析BeatuifulSoup,不需要考虑前端形式的一种获取元素的方法

1.beatuifulSoup 基本用法 beautifulSoup(简称bs4)是python的一个第三方库,用于解析html和xml文档中提取数据的python库。它能够将复杂的文档转化为树形结构,方便快速定位和提取所需数据以及查找和修改,常常与爬虫框架…

Ubuntu共享文件夹权限设置

在Ubuntu中设置共享文件夹的权限(只读、读写、无权限),主要通过两种方式实现:‌文件系统权限‌和‌Samba共享配置‌。以下是详细步骤:‌一、文件系统权限设置(基础权限)‌1. ‌修改文件夹所有权…

小程序点击菜单栏实现样式动态切换

小程序点击菜单栏背景样式动态切换 前言:今天做一个小程序项目,要做一个菜单栏动态切换的功能,因为这种需求很常见,这次干脆记录一下,帮助别人的同时,自己下次也可以直接照搬使用。 效果截图如下&#xff1…

掌握工程化固件烧录,开启你的技术进阶之路-FPGA ISE(xilinx)

1、电脑需先行安装ISE14.7。若已完成安装,此步骤可略过;若尚未安装,在后续章节会介绍如何安装ISE,由于ISE14.7的安装程序体量庞大,可借助U盘进行传输。同时,电脑需预留至少30G的存储空间以用于安装该程序。…