《Windows核心编程》第9章 用内核对象进行线程同步

《Windows核心编程》读书笔记 这篇笔记是我在读《Windows核心编程》第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入,但应该是合理的。开头几章由于追求简洁,往往是很多单独的字句,后面的内容更为连贯。   海量细节。     第1章    错误处理 1.         GetLastError返回的是最后的错误码,即更 阅读详情

在用户模式下进行线程同步的好处就是速度快。如果关心应用程序的性能,则应该优先考虑在用户模式下的同步机制能否适用。

内核对象都有触发和未触发两种状态,微软创建了一些规则,用来规定如何在这两种状态之间进行转换。比如,进程(线程)内核对象在创建的时候总是处于未触发状态。当进程(线程)终止的时候,操作系统会自动使进程(线程)内核对象变成触发状态。当进程(线程)内核对象被触发后,它将永远保持这种状态,再也不会变回到为触发状态。

等待函数使一个线程自愿进入等待状态,直到指定的内核对象被触发为止。如果线程在调用一个等待函数时,相应的内核对象已经处于触发状态,那么线程是不会进入等待状态的。

WaitForSingleObject(HANDLE hObject,DWORD dwMillseconds)是最常用的等待函数。该函数的返回值表示为什么调用线程又能够继续执行。如果是因为线程等待的对象被触发,那么返回值是WAIT_OBJECT_0;如果是因为等待超时,那么返回值是WAIT_TIMECOUT。如果给该函数传入了无效参数,那么返回值是WAIT_FAILED(这时可以调用GetLastError得到更详细的信息)。

如果允许调用线程同时检查多个内核对象的触发状态,我们可以调用函数WaitForMultipleObjects。可以通过两种不同方式来使用这个函数:一种是让线程进入等待状态直到指定内核对象中的一个被触发为止,另一种是让线程进入等待状态直到指定内核对象中的全部被触发为止。如果返回值既不是WAIT_TIMECOUT,也不是WAIT_FAILED,那么我们应该把返回值减去WAIT_OBJECT_0。得到的数值是我们在第二个参数中传递的句柄数组的索引,用来告诉我们被触发的是哪个对象。

WaitForMultipleObjects是以原子方式工作的。当函数检查内核对象的状态时,任何其他线程都不能再背后修改对象的状态。这样可以防止死锁情况的发生。

多个线程等待同一个内核对象时,那么当对象被触发时,系统如何决定应该唤醒哪个线程?微软回答是:算法是公平的,也就是说每个线程都有可能被唤醒。与线程优先级以及等待时间长短都没有关系。但是实际上,微软使用算法的机制是“先入先出”。

事件内核对象包含一个使用计数,一个用来表示事件是自动重置事件还是手动重置事件的布尔值,以及另一个用来表示事件有没有被触发的布尔值。当一个手动重置事件被触发的时候,正在等待该事件的所有线程都将变成可调度状态,而当一个自动重置事件被触发的时候,只有一个正在等待该事件的线程会变成可调度状态。

事件最通常的用途是,让一个线程执行初始化工作,然后再触发另一个线程,让它执行剩余工作。开始我们将事件初始化为未触发状态,然后当线程完成初始化工作的时候,触发事件。此时另一个线程一直等待该事件,它发现事件被触发,于是变成可调度状态。

函数PulseEvent会先触发事件然后立刻将其恢复到未触发状态,相当于在调用SetEvent之后立即调用ResetEvent一样。

可等待计时器是一种内核对象,它会在某个指定的时间触发,或每隔一段时间触发一次。它们通常用来在某个时间执行一些操作。要创建可等待的计时器,可以调用CreateWaitableTimer函数。也可以调用OpenWaitableTimer函数来得到一个已经存在的可等待计时器的句柄,该句柄与当前进程相关联。可以创建手动重置或自动重置的计时器。当手动重置计时器被触发时,正等待在该计时器的所有线程都变成可调度状态;当自动重置计时器被触发时,只有一个正等待在该计时器的线程会变成可调度状态。

可等待计时器在创建时,总是处于未触发状态。如果要想触发计时器,我们可以调用SetWaitableTimer函数。可以在该函数中指定计时器第一次触发的时间,以及之后计时器以怎样的频度触发。第一次触发的时间可以是绝对时间,也可以指定一个相对时间。如果希望计时器只触发一次,可以将触发频度参数传0值,然后调用CloseHandle关闭计时器。

调用CancelWaitableTimer会把句柄标识的计时器取消,这样计时器就永远不会触发了,除非后来再调用SetWaitableTimer来对它进行重置。

微软允许计时器把一个异步过程调用APC放到SetWaitableTimer的调用线程的队列中。只需要实现一个计时器的APC函数,将函数的地址传给SetWaitableTimer的参数pfnCompletionRoutine。当计时器被触发的时候,当且仅当SetWaitableTimer的调用线程正好处于可提醒状态时(即线程必须是由于调用SleepEx、WaitForSingleObjectEx、WaitForMultipleObjectEx、MsgWaitForMultipleObjectsEx、SignalObjectAndWait而进入的等待状态),这个APC函数才会被调用线程调用。

线程不应该在等待一个计时器句柄的同时以可提醒的方式等待同一个计时器。

可等待计时器和用户计时器(通过SetTimer函数来设置)的最大区别:用户计时器需要在应用程序中使用大量的用户界面基础设施,从而消耗更多的资源。而可等待计时器是内核对象,它可以在多个线程间共享,而且具备安全性。

信号量内核对象用来对资源进行计数。它包含一个使用计数,还包含另外两个32位值:一个最大资源计数和一个当前资源计数。最大资源计数表示信号量可以控制的最大资源数量,当前资源计数表示信号量当前可用资源的数量。可以使用CreateSemaphore或CreateSemaphoreEx来创建一个信号量,可以使用OpenSemaphore来得到一个已经存在的信号量的句柄。

信号量的规则:
●    如果当前资源计数大于0,那么信号量处于触发状态
●    如果当期资源计数等于0,那么信号量处于未触发状态
●    系统绝对不会让当前资源计数变为负数
●    当期资源计数绝对不会大于最大资源计数

线程通过调用ReleaseSemaphore来递增信号量的当前资源计数。我们无法在不改变当前资源数的前提下来得到信号量的当前资源计数值。

互斥量内核对象用来确保一个线程独占对一个资源的访问。互斥量对象包含一个使用计数、线程ID以及一个递归计数。互斥量与关键段的行完全相同。互斥量是内核对象,关键段时用户模式下的同步对象,所以互斥量比关键段慢。同时不同进程中的线程可以访问同一个互斥量,线程可以在等待对资源的访问权时指定一个最长等待时间,关键段则做不到这些。线程ID用来标识当前占用这个互斥量的是系统中的哪个线程,递归计数表示这个线程占用该互斥量的次数。

互斥量的规则:
●    如果线程ID为0,那么该互斥量不为任何线程所占用,它处于触发状态。
●    如果线程ID为非零值,那么有一个线程已经占用了该互斥量,它处于未触发状态。
●    与所有其他内核对象不同,操作系统对互斥量进行了特殊处理,允许它们违反一些常规。

函数CreateMutex用来创建一个互斥量。也可以调用OpenMutex来得到一个已经存在的互斥量的句柄,该句柄与当前进程相关联。

系统检查想要获得互斥量的线程的线程ID与互斥量对象内部记录的线程ID是否相同。如果线程ID一致,那么系统会让线程保持可调度状态—即使该互斥量尚未出发。每次线程成功等待了一个互斥量,互斥量对象的递归计数会递增。使递归计数大于1的唯一途径是利用这个例外,让线程多次等待同一个互斥量。

如果当前占有访问权的线程不再需要访问资源的时候,必须调用ReleaseMutex函数来释放互斥量。这个函数会将对象的递归计数减1。如果线程成功地等待了互斥量对象不止一次,那么线程必须调用ReleaseMutex相同的次数才能使对象的递归计数变为0。当递归计数变为0的时候,函数还会将线程ID设为0,这样就会触发该互斥量对象。

互斥量对象与其他内核对象不同,它们具有“线程所有权”的概念。除了互斥量,没有任何一个内核对象会记住自己是哪个线程等待成功的。这种特殊性使得互斥量即使在未触发的状态下,也能为线程所获得。如果占用互斥量的线程在释放互斥量之前终止,系统会认为互斥量被遗弃了,这时系统会自动将互斥量对象的线程ID设为0,将它的递归计数设为0,然后检查有无其他线程正在等待该互斥量。如果有,系统会公平选择一个正在等待的线程,把对象内部的线程ID设为所选择线程的线程ID,把递归计数设为1,这样被选择的线程变为可调度状态。

线程同步对象速查表

注意:用户模式下的Interlocked系列函数不会使线程变成不可调度状态,它们只是修改一个值并立即返回。

异步设备I/O允许线程开始读取操作或写入操作,但不必等待读取操作或写入操作完成。设备对象是可同步的内核对象,我们可以调用WaitForSingleObject并传入文件句柄、套接字、通讯端口等等。当系统异步执行I/O时,设备对象处于未触发状态。而一旦操作完成,系统就会将对象变成触发状态,这样线程就知道操作完成了。然后线程就可以继续执行。

线程可以调用WaitForInputIdle函数来将自己挂起。该函数原型为:
DWORD WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds);
这个函数会等待由hProcess标识的进程,直到创建应用程序第一个窗口的线程中没有待处理的输入为止。应用场景举例:父进程可以创建一个子进程来完成一些工作。当父进程调用CreateProcess的时候,父进程可以一边继续执行,一边让子进程进行初始化。父进程可能需要得到子进程创建的窗口句柄。父进程能够知道子进程已经初始化完毕的唯一方法就是等待子进程,直到它不再处理任何输入为止。因此可在调用CreateProcess之后,父进程调用WaitForInputIdle。

线程也可以调用MsgWaitForMultipleObjects(Ex)函数,这使得线程等待需要自己处理的消息。这类函数不仅内核对象被触发时,调用线程会变成可调度状态,而且当窗口消息需要被派送到一个由调用线程创建的窗口时,它们也会变成可调度状态。

创建窗口的线程和执行与用户界面相关任务的线程不应该使用WaitForMultipleObjects,而应该使用MsgWaitForMultipleObjectsEx。因为前者会妨碍线程对用户在界面上的操作进行响应。

SignalObjectAndWait函数会通过一个原子操作来触发一个内核对象并等待另一个内核对象。SignalObjectAndWait函数原型为:DWORD SignalObjectAndWait(
HANDLE hObjectToSignal,//必须是一个互斥量、信号量或事件对应的句柄
HANDLE hObjectToWaitOn,//可以标志的内核对象:互斥量、信号量、事件、计时器、进程、线程、作业、控制台输入以及变更通知
DWORD dwMilliseconds,//函数等待对象触发的最长时间
BOOL bAlertable//当线程处于等待状态时,是否应该能够对添加到队列中的异步过程调用进行处理
);

微软提供了一组新的等待链遍历(WCT)API,这些函数可以让我们列出所有的锁,并检测进程内部,甚至是进程之间的死锁。 

WCF 所记录的同步机制的类型如下

气象数据收集 国家气象信息中心-中国气象数据网 (cma.cn)国家气象信息中心-中国气象数据网 (cma.cn)预报数据:需要定制,收费10万+路面数据同化系统,实时。 阅读详情

相关推荐

从零搭建Python接口自动化测试框架:pytest+requests+Allure实战指南

接口自动化测试是现代软件工程中保障交付质量、提升测试效率的核心实践。其基本原理是通过脚本模拟客户端请求,对服务端接口进行自动化的功能验证、性能探测与回归测试,从而替代重复的手工操作。在技术实现上,Python凭借其简洁语法和丰富的生态,成为构建此类框架的主流选择,其中pytest测试框架、requests HTTP库和Allure报告工具构成了技术栈的黄金组合。这套技术方案的价值在于,它能将测试用例数据(如YAML文件)与执行逻辑分离,实现数据驱动测试,并通过持续集成(如Jenkins)无缝融入DevOps

weixin_31822733的博客 378

WaitForSingleObject和WaitForMultipleObjects使用详解

WaitForSingleObject的用法DWORD WaitForSingleObject(  HANDLE hHandle,  DWORD dwMilliseconds);参数hHandle是一个事件的句柄,第二个参数dwMilliseconds是时间间隔。如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT

egxsun的专栏 8032

衡山派Luban-Lite系统SDIO无线网络配置实战:以D133CBV-QFN88开发板与RTL8189模组为例

本文详细介绍了在衡山派D133CBV-QFN88开发板上,为Luban-Lite系统配置SDIO无线网络的完整实战流程。通过配置SDMC接口、RTL8189 Wi-Fi驱动、lwIP协议栈及内核参数,并解决编译分区问题,最终实现Wi-Fi网络连接与测试,为嵌入式设备联网提供清晰指导。

weixin_35677363的博客 267

WaitForMultipleObjects用法详解

WaitForMultipleObjects是Windows中的一个功能非常强大的函数,几乎可以等待Windows中的所有的内核对象 函数原型为: DWORD WaitForMultipleObjects( DWORD nCount, // number of handles in the handle array CONST HANDLE *lpHandl...

u014311306的博客 3万+

嵌入式AI实战:基于RK3588部署YOLOv11并集成OpenCV实现实时推理(全流程详解)

本文详细介绍了在RK3588芯片上部署YOLOv11目标检测模型的全流程,包括环境搭建、模型转换和实时推理实现。主要内容为:1)通过YOLOv11官方工具将PyTorch模型转为ONNX格式;2)使用RKNN Toolkit2将ONNX模型转换为适配RK3588的RKNN格式;3)在RK3588上结合OpenCV实现实时视频推理功能。教程提供了完整的代码示例和详细步骤说明,帮助开发者快速在边缘设备上部署目标检测模型,实现AI视觉应用的落地。

LXY_LOVE36的博客 213

SetWaitableTimer函数非凝滞定时

1'clsWaitableTimer.cls中代码23OptionExplicit4PrivateTypeFILETIME5dwLowDateTimeAsLong6dwHighDateTimeAsLong7EndType89PrivateConstWAIT_ABANDONED&=&...

weixin_30902675的博客 187

Qt实现窗口自适应分辨率大小

如果希望窗口大小始终保持与屏幕分辨率一致,可以将上述代码放在窗口的resizeEvent()函数中。这样,每当窗口大小发生变化时,都会自动调用resizeEvent()函数,从而实现窗口大小的自适应调整。在Qt中,可以通过一些简单的方法实现窗口大小随分辨率变化而自适应调整。获取到当前屏幕的分辨率后,可以根据需要调整窗口的大小。无论在何种分辨率下运行应用程序,窗口都能够正确地自动调整大小,提供更好的用户体验。除了调整窗口大小,还可以考虑将窗口设置为最大化,以充分利用屏幕空间。步骤2:调整窗口大小。

FuJavascript的博客 3655

SetWaitableTimer 的用法

定时器

lizhihaoweiwei的专栏 3147

时间序列—显著相关性和滞后性分析_python

本文讲述了两个时间序列(信号)的相关性分析,可以利用相关性分析进行特征筛选。此外本文还讲了怎么判断时间序列的滞后性的方法。

qq_34229228的博客 2万+

23、资产分散化与有效前沿:投资组合优化的核心策略

本文深入探讨了现代投资组合理论的核心概念,包括分散投资的重要性、均值-方差优化框架以及有效前沿的构建与应用。通过案例分析和数学模型,阐述了如何通过科学方法降低投资组合风险并实现最优风险收益权衡。文章还介绍了实际应用中的求解方法与决策流程,为投资者提供系统的投资组合优化指导。

cc789的博客 114

Windows核心编程:第9章 用内核对象进行线程同步

Github https://github.com/gongluck/Windows-Core-Program.git //第9章 用内核对象进行线程同步.cpp: 定义应用程序的入口点。 // #include "stdafx.h" #include "第9章 用内核对象进行线程同步.h" #include <Wct.h> DWORD WINAPI Thread(PVOID pa...

weixin_30763455的博客 146

2021年03月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0。n的位数为m。现在从m位中删除k位(0

人生就是一个不断学习的过程 1011

《Windows核心编程》读书笔记(六) 第9章 线程与内核对象的同步

第9章 线程与内核对象的同步 用户方式同步的优点是它的同步速度非常快。如果强调线程的运行速度,那么首先应该确定用户方式的线程同步机制是否适合需要   互锁函数家族只能在单值上运行,根本无法使线程进入等待状态。可以使用关键代码段使线程进入等待状态,但是只能用这些代码段对单个进程中的线程实施同步。还有,使用关键代码段时,很容易陷入死锁状态,因为在等待进入关键代码段时无法设定超时值。   内核

I feel lost 299

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

《Windows核心编程 5th》读书笔记----第9章 用内核对象进行线程同步

用户模式与内核模式下的线程同步 首先,先引用一下《深入理解计算机系统 2nd》第8章 “异常控制流”关于用户模式和内核模式的一段话,理清一下关于用户模式和内核模式的概念: 为了使操作系统内核提供一个无懈可击的进程抽象,处理器必须提供一种机制,限制一个应用可以执行的指令以及它可以访问的地址空间范围。 处理器通常是用某一个控制寄存器中的一个模式位(mode bit)来提供这个功能的,该寄存器描述

劉俊的专栏 1082

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

windows 核心编程之9 内核对象用于线程同步

内核对象用于线程同步 1

软件开发 1145

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

windows核心编程

主要用于记录windows核心编程这本书籍的学习。

weixin_45002961的博客 1341

windows核心编程之线程同步

来源:微信公众号「编程学习基地」 线程同步线程同步临界区使用示例互斥函数事件内核对象 线程同步 线程不同步会出现什么情况呢? #include <stdio.h> #include <windows.h> static int count = 20; const unsigned int MAX = 4; // 线程函数 DWORD WINAPI ThreadProc(LPVOID lpParam) { while (count >= 0) { printf("..

deroy 548

Windows核心编程【9】小结

第九章 用内核对象进行线程同步 1、在用户模式下进行线程同步的最大好处就是速度非常快。如果关心应用程序的兴宁,那么应该先看看用户模式下的同步机制能否适用。 2、但是用户模式下的同步机制存在一些局限性。例如,对Interlocked系列函数只能对一个值进行操作,它们从来不会把线程切换到等待状态。我们可以用关键段来把线程切换到等待状态,但是它们只能用来对同一个进程中的线程进行同步。此外,在

BetaBin 2815

Windows核心编程 第九章 线程与内核对象的同步(上)

第9章线程与内核对象的同步 上一章介绍了如何使用允许线程保留在用户方式中的机制来实现线程同步的方法。用户方式同步的优点是它的同步速度非常快。如果强调线程的运行速度,那么首先应该确定用户方式的线程同步机制是否适合需要。 虽然用户方式的线程同步机制具有速度快的优点,但是它也有其局限性。对于许...

墨鱼菜鸡 265

《Windows核心编程》读书笔记九 用内核模式进行线程同步

第九章 用内核对象进行线程同步 本章内容 9.1 等待函数 9.2 等待成功锁引起的副作用 9.3 事件内核对象 9.4 可等待的计时器内核对象 9.5 信号量内核对象 9.6 互斥量内核对象 9.7 线程同步对象速查表 9.8 其他的线程同步函数 用户模式下的线程同步高性能,但是存在一些局限。例如无法进行进程间线程的同步,Iterlocked系函数不会把线程切

sesiria的博客 560

Windows核心编程 第九章 线程与内核对象的同步(下)

9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象。它们通常用来在某个时间执行某个操作。 若要创建等待定时器,只需要调用C r e a t e Wa i t a b l e Ti m e r函数: HANDLE CreateWaitableTi...

墨鱼菜鸡 419

线程与内核对象的同步——Windows核心编程学习手札之九

线程与内核对象的同步——Windows核心编程学习手札之九用户方式下的线程同步机制具有速度快的特点,但有其局限性,对于许多应用程序来说,并不合适。例如,互锁函数家族只能在单值上运行,根本无法使线程进入等待状态;关键代码可以使线程进入等待状态,但只能用关键代码段对单个进程中的线程实施同步,使用关键代码段也容易陷入死锁,因为在等待进入关键代码段时无法设定超时值。内核方式下的线程同步机制适应性要

医疗影像检索 3660

Windows核心编程_内核对象

windows核心编程_内核对象:概念、引用计数、安全控制、创建、关闭、跨进程边界共享、名字空间

2401_83891037的博客 415

Windows核心编程 用内核对象进行线程同步

用户模式的线程同步机制: 优点:速度快,可保持在用户模式,无需切换到内核模式。 缺点:不适用于许多应用程序,不支持多个进程间的同步。 内核对象的唯一缺点就是性能:X86上,一个空的系统调用会占约200个CPU周期(原因是用户模式切换到内核模式时,伴随调度新线程而来的刷新高速缓存以及错过高速缓存(未命中))。         几乎所有的内核对象都可以进行线程同步。这些内核对象都包括两种状态:

fztfztfzt的专栏 1294

windows核心编程9

 第9章 线程与内核对象的同步上一章介绍了如何使用允许线程保留在用户方式中的机制来实现线程同步的方法。用户方式同步的优点是它的同步速度非常快。如果强调线程的运行速度,那么首先应该确定用户方式的线程同步机制是否适合需要。 虽然用户方式的线程同步机制具有速度快的优点,但是它也有其局限性。对于许多应用程序来说,这种机制是不适用的。例如,互锁函数家族只能在单值上运行,根本无法使线程进入等待

freedom0203的专栏 699
上一篇: 《Windows核心编程》第8章 用户模式下的线程同步
下一篇: 编程思想:从实例谈面向对象编程(OOP)、工厂模式和重构
sockpuppet007
博客等级 码龄16年 4粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值