Windows编程之线程
本笔记整理自:《Windows核心编程(第五版)》
何为线程
- 线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。每一个进程至少包含一个线程。
- 主线程是以main、wmain、WinMain或wWinMain作为入口的线程。
- 线程即为程序作业的一道流程。程序(可以认为是一个进程)可以包含多个线程,这几个线程根据优先级与状态,有次序的利用CPU执行相应工作。
线程的开始和结束
创建线程
- CreateThread:Windows函数
/*
* include:Windows.h
* 创建一个线程(操作系统级别的API)
* @params:
* psa : 指向 PSECURITY_ATTRIBUTES 结构体的指针。传入 NULL为默认
* cbStackSize : 指定线程可以为其线程栈使用多少地址空间
* pfnStartAddr: 线程的函数入口地址
* pvParam : 函数入口的参数
* dwCreateFlags : 创建线程的标志
* pdwThreadID : 返回创建线程的ID
*/
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD cbStackSize,
PTHREAD_START_ROYTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreateFlags,
PDWORD pdwThreadID
);
//samples:
DWORD thread_id;
HANDLE thread_handle;
thread_handle = CreateThread(NULL, 2, ThreadFunc, NULL, CREATE_SUSPENDED, &thread_id);
if (thread_handle)
ResumeThread(thread_handle);
- _beginthreadex:C-Rumtime Library函数 (建议使用)
/*
* include:process.h
* 创建一个线程(操作系统级别的API)
* @params:
* security : 安全属性, 为NULL时表示默认安全性
* stack_size : 线程的堆栈大小, 一般默认为0
* start_address: 所要启动的线程函数
* argilist : 线程函数的参数, 是一个void*类型, 传递多个参数时用结构体
* initflag : 新线程的初始状态,0表示立即执行,CREATE_SUSPENDED表示创建之后挂起
* threaddr : 用来接收线程ID
*/
_beginthreadex
void *security,
unsigned stack_size,
unsigned(_stdcall *start_address)(void *),
void *argilist,
unsigned initflag,
unsigned *threaddr
);
终止线程
方法(后面的三种都是“强杀”,不建议这么做)
- 线程函数返回(最自然的一种方法,最好这么做)
- 自身线程调用ExitThread
- 同一个进程或另一个进程的线程调用TerminateThread
- 包含线程的进程终止运行
线程函数返回
static unsigned _stdcall ThreadEnterProc(void* param)
{
while(!IsStop)
{
//TO-DO
//...
}
return 0; //自然退出
}
- ExitThread:线程自身调用,用于自我关闭
VOID ExitThread(DWORD dwExitCode); //哪个线程调用此函数就意味着要关闭哪一个线程(“自杀”)
- TerminateThread:终止某线程。
注意此函数是异步的,因此就算返回了true,只能证明它响应了此操作,但不能保证线程已经停止运行
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
线程运行时的调度和线程优先级
挂起(暂停)、恢复与睡眠
- 创建挂起的线程,可以让我们在恢复前修改线程的属性信息。
- 线程可以自己调用函数挂起,但不能自己恢复。
- 一个线程可以最多被挂起 MAXIMUM_SUSPEND_COUNT 次
- 应用程序使用挂起操作时必须要小心,要明确知道正在进行什么操作。
挂起
/*
* @param:
* hThread:想要挂起的线程句柄
* @return
* 返回线程的前一个挂起计数(注意是前一个)
*/
DWORD SuspendThread(HANDLE hThread);
恢复
/*
* @param:
* hThread:想要恢复的线程句柄
*
* @return
* 如果线程恢复成功,它将返回线程的前一个挂起计数(线程可以被多次挂起,因此这个返回值可以提示我们还要恢复几次才能获得 CPU 资源)
* 否则,它将返回 0xFFFFFFFF
*/
DWORD ResumeThread(HANDLE hThread);
睡眠
- 调用Sleep,将使用线程自愿放弃属于它的时间片中剩下的部分
- Sleep的精确度是较低的(近似于所设定的毫秒),苏醒取决于当前系统其他线程的情况.
- 传入参数:INFINITE是在告诉系统,永远不要分配 CPU 给这个系统
- Sleep可以传递0,表示放弃时间片的剩余部分(以等待下一次轮询),CPU将让让渡给优先度相对或更高的线程。
基于上面对线程睡眠的解释,我们应该了解到,Sleep(milliseconds)并不意味着线程要暂停milliseconds。而是在milliseconds的时间内放弃占用CPU。milliseconds后此线程加入到线程待轮询队列,等待使用CPU。
/*
* 将进程挂起dwMilliseconds的事件
*
* @param
* dwMilliseconds : 睡眠时间
*/
DWORD Sleep(DWORD dwMilliseconds);
线程切换
- 线程切换相当于Sleep(0),但不同的点是线程切换忽略了优先级,它可以给优先级低的线程让出CPU。
- 如果存在另一个可调度线程,那么系统会让此线程运行。
- 调用函数时,系统查看是否存在正急需 CPU 时间的饥饿线程。如果没有,SwitchToThread立即返回。如果存在,SwitchToThread则调度该线程(忽略优先级)
BOOL SwitchToThread();
线程优先级
Windows支持的线程相对优先级
| 相对线程优先级 | 符号常数 | 描述 |
|---|---|---|
| time-critical | THREAD PRIORITY_ TIME CRITICAL | 对于real-time优先级类,线程运行在31上;所有其他优先级运行在15 |
| highest | THREAD_ PRIORITY_ HIGHEST | 线程运行在高于normal之上一个级别 |
| above normal | THREAD PRIORITY_ ABOVE_ NORMAL | 线程运行在高于normal之上一个级别 |
| normal | THREAD PRIORITY_ NORMAL | 线程运行在进程normal级别上 |
| below normal | THREAD PRIORITY_ BELOW_ NORMAL | 线程运行在低于normal之下一一个级别 |
| lowest | THREAD_ PRIORITY_ LOWEST | 线程运行在低于normal之下两个级别 |
| idle | THREAD_ PRIORITY_ IDLE | 对于real-time优先级类,线程运行在16;所有其他优先级运行在1 |
设置线程优先级
BOOL SetThreadPriority(
HANDLE hThread,
int nPriority
);
是否启用动态提升优先级
/*
* 启用or禁止动态提升优先级
*
* @param
* hThread : 线程句柄
* bDisablePriorityBoost : 是否禁止。TRUE为禁用,FALSE为启用。
*/
BOOL SetThreadPriorityBoost(HANDLE hThread,BOOL bDisablePriorityBoost);
获取线程信息
线程句柄
HANDLE GetCurrentThread();
线程ID
DWORD GetCurrentThreadId();
线程状态
/*
* @params:
* hThread : 线程句柄
* pdwExitCode : 线程退出状态
*
* Descriptions:
* 若线程未终止,则 pdwExitCode == STILL_ACTIVE
*/
BOOL GetExitCodeThread(HANDLE hThread,PDWORD pdwExitCode);
线程优先级
//获取当前线程优先级
int GetThreadPriority(HANDLE hThread);
线程上下文
/*
* @Descriptions:获取当前想成上下文
*
* @Notes:调用时请先挂起线程
*/
BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContent);
线程的运行时间
/*
* @Descriptions:获取进程、线程的时间信息
*
* @params:
* ftCreationTime :创建时间
* ftExitTime: 退出时间,运行时推出时间是没有定义的
* ftKernelTime : 线程执行内核模式下的操作系统代码所用时间
* ftUserTime : 线程执行用户代码所用时间的绝对值
*/
GetThreadTimes(GetCurrentThread(), &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);
其他:句柄复制
/*
* 注意:因为创建了一个句柄,使用计数+1,因此,当使用完成后需要调用 CloseHandle()
*/
BOOL DuplicateHandle
(
HANDLE hSourceProcess,
HANDLE hSource,
HANDLE hTargetProcess,
PHANDLE phTarget,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions
);
//sample
HANDLE hCurrentThread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
//as Params And Use It,You must do:
CloseHandle(hCurrentThread);
Windows编程之线程的更多相关文章
- Windows编程之线程同步
本笔记整理自:<Windows核心编程(第五版)> 目录 什么是线程同步 用户方式中的线程同步 原子访问:Interlocked系列函数 CRITICAL_SECTION:关键段 内核对象 ...
- Direct3D 10学习笔记(四)——Windows编程
本篇将简单整理基本的Windows应用程序的实现,并作为创建Direct3D 10应用程序的铺垫.具体内容参照< Introduction to 3D Game Programming with ...
- .NET面试题解析(07)-多线程编程与线程同步
系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等, ...
- windows编程注意点(持续更新)
1.windows编程中,所有的操作都放到窗口过程中进行,main函数只用于描述窗口基本信息. 2.用于获取设备环境句柄时,用BeginPaint/EndPaint,消耗cpu小,但占内存大;用Get ...
- .NET面试题解析(07)-多线程编程与线程同步 (转)
http://www.cnblogs.com/anding/p/5301754.html 系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实 ...
- 操作系统,windows编程,网络,socket
首发:个人博客,更新&纠错&回复 之前关于c/s的一篇博文只记了思路没记代码,而且表达不清晰,事后看不知所云,这个习惯要改. 这十几天学了点关于操作系统.windows编程和网络,主要 ...
- Win32多线程编程(2) — 线程控制
Win32线程控制只有是围绕线程这一内核对象的创建.挂起.恢复.终结以及通信等操作,这些操作都依赖于Win32操作系统提供的一组API和具体编译器的C运行时库函数.本篇围绕这些操作接口介绍在Windo ...
- Win32多线程编程(3) — 线程同步与通信
一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...
- 有一定基础的 C++ 学习者该怎样学习 Windows 编程?
人的心理有个奇异的特性:一项知识一旦学会之后,学习过程中面临的困惑和不解非常快就会忘得干干净净,似乎一切都是自然而然,本来就该这种.因此,关于「怎样入门」这类问题,找顶尖高手来回答,未必能比一个刚入门 ...
随机推荐
- KTL 一个支持C++14编辑公式的K线技术工具平台 - 第七版,体验GPGPU。
K,K线,Candle蜡烛图. T,技术分析,工具平台 L,公式Language语言使用c++14,Lite小巧简易. 项目仓库:https://github.com/bbqz007/KTL 国内仓库 ...
- 令你瞠目结舌的 Python 代码技巧
0. for-else 在 Python 中,else 不仅可以与 if 搭配使用,还可以与 for 结合. python答疑 咨询 学习交流群2:660193417### for x in rang ...
- NC20241 [SCOI2005]扫雷MINE
NC20241 [SCOI2005]扫雷MINE 题目 题目描述 相信大家都玩过扫雷的游戏.那是在一个 \(n \times m\) 的矩阵里面有一些雷,要你根据一些信息找出雷来. 万圣节到了 ,&q ...
- IDEA的项目结构和IDEA的HelloWord
IDEA首次驱动 1. 选择不导入任何设置,点击 OK 2. 选择 Create New Project 3. 点击 new 按钮,配置安装的 JDK9 版本 选择 JDK9 目录,点击确定 4. 不 ...
- SSH远程连接学校实验室服务器 一 python版本问题
问题1: 连接上远程服务器后,输入 python 发现python版本只有2.7 .试图使用以下方式更新: sudo apt install python3.9 会出现如下报错信息: 解决方式: 一般 ...
- Qt点名器
项目已开源,点击跳转 废话不多说,直接上代码. CMakeLists.txt cmake_minimum_required(VERSION 3.10) project(qt-caller) find_ ...
- npm相关资料
npm 源的配置 命令行模式 npm install XXX --registry https://registry.npmmirror.com/ 项目模式 在项目更目录新建.npmrc 文件,内容 ...
- BUCK 电路PSIM仿真模型搭建之一 (PI模块稳定性分析)
1. 利用PI 模块仿真BUCK 电路电流环 在调制通道上未加入延迟环节时,无论KP, KI 参数如何调整系统都是稳定的 仿真结果: 在调制通道上引入 一个开关周期的延迟 系统出现明显的震荡情况,说 ...
- 【我的面试-01】Web前端开发实习岗-面试题总结
简单开头 首先技术面试官会根据简历里所写的项目和个人掌握技术栈提问(我不知道已经改过多少次简历了,因为前期投简历是真的是沉在茫茫大海,捞漂流瓶都捞不到的那种) 我的技术栈:(Vue还在苦苦的自学当中, ...
- github碰到的问题
下载问题 自己编译一下 mvn clear mvn compile mvn package 自己编译之后的文件,然后解压即可,第一次自己傻傻的,直接用源码跑,少报错! 项目预览问题 添加1s即可 下载 ...