创建线程、线程的挂起与恢复、线程的优先级与终止线程
目录
一、创建线程
CreateThread函数:
下面是示例:
编辑
ThreadProc函数解释:
DWORD的本质是 unsigned long PVOID的本质是 void*
二、线程的终止
1.WaitForSingleObject()函数:
示例如下:
2.ExitThread()函数:
示例如下:
3.TerminateThread()函数:
4.CloseHandle()函数:
5.正常return 0;
三、线程的恢复与挂起
1.挂起线程:
①SuspendedThread()函数:
示例如下:
②CreateThread()的第五个参数设为CEREATE_SUSPENDED
四、线程的优先级
一、创建线程
CreateThread函数:
该函数用于创建一个新的线程并在其上运行指定的函数,其返回值是HANDLE类型(句柄),原型如下:
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);
第一个参数:
指向SECURITY_ATTRIBUTES形态的结构的指针,表示线程内核对象的安全属性
windows 98忽略该参数,windows NT中设为NULL表示使用默认安全属性第二个参数:
初始该线程的堆栈大小,以字节为单位,默认为0即使用默认大小(1MB),在任何情况下,OS会动态延长堆栈大小第三个参数:
是一个指向线程函数的指针。线程将从此函数的入口点开始执行。
函数名称无限制,但必须是以下形式声明:
DWORD WINAPI ThreadProc(PVOID pParam);第四个参数:
传递给线程函数(第三个函数的参数)的参数,是一个指针类型。第五个参数:
线程的创建标志,通常设置为0即可,可选参数如下:
0(或CREATE_SUSPENDED):默认值,创建线程后立即执行线程函数。CREATE_SUSPENDED:创建线程后暂停线程的执行,需要通过ResumeThread激活线程。
CREATE_DETACHED:创建一个分离的线程,不需要手动释放线程资源。
STACK_SIZE_PARAM_IS_A_RESERVATION:将dwStackSize参数解释为堆栈的保留大小。
CREATE_NEW_CONSOLE:创建一个新的控制台窗口,使线程在独立的控制台环境中运行。
CREATE_UNICODE_ENVIRONMENT:使用Unicode字符集解析环境字符串。
第六个参数:
一个指向DWORD类型的指针,用于接收新线程的标识符(ID)
将返回线程的ID号,传入NULL表示不需要返回该线程ID号
下面是示例:
#include <iostream>
#include <windows.h> //调用windows API的头文件
using namespace std;//线程函数,格式固定
DWORD WINAPI ThreadProc(PVOID lp){//线程的主体//…………return 0;
};int main()
{CreateThread(NULL, 0, ThreadProc, NULL, 0, 0);return 0;
}
ThreadProc函数解释:
该函数即线程入口,ThreadProc 和 lp一样, 名字随意, ThreadProc函数本身作为CreateThread函数的第三个参数,该函数参数由CreateThread函数的第四个参数传入
DWORD的本质是 unsigned long
PVOID的本质是 void*
注意:在多线程环境中,全局变量是所有线程共享的,这意味着多个线程可以同时访问和修改这些全局变量。因为线程是并发的,所以当一个线程在执行过程中修改了全局变量的值时,其他线程在访问同一全局变量时可能会读取到这个修改后的值。
如果一个线程使用new在堆上分配了内存,并在线程执行过程中释放了这块内存,那么其他线程在访问这块内存时可能会遇到悬挂指针(dangling pointer)或无效内存访问的问题
因此,在多线程编程中,对于共享的资源,包括全局变量和动态分配的内存(如new操作),必须非常小心。应该通过合适的同步机制(例如互斥锁、条件变量等)来确保多个线程对这些资源的安全访问。这样可以避免潜在的竞态条件和访问无效内存的问题。
在处理动态内存时,最好的做法是由创建它的线程负责释放内存,而不是在其他线程中释放。此外,可以使用智能指针(例如std::shared_ptr或std::unique_ptr)来管理动态内存,这样可以避免手动释放内存的问题。
二、线程的终止
1.WaitForSingleObject()函数:
函数原型如下:
DWORD WaitForSingleObject(
HANDLE hHandle, // 要等待的内核对象的句柄,这里是线程句柄
DWORD dwMilliseconds // 等待的时间,以毫秒为单位,INFINITE 表示无限等待
);
第二个参数 dwMilliseconds 表示等待的时间,以毫秒为单位。这个参数控制函数在等待对象状态变化时的行为:
- 如果
dwMilliseconds的值为INFINITE(-1),则WaitForSingleObject会一直阻塞,直到内核对象的状态发生变化。 - 如果
dwMilliseconds的值为 0,则函数立即检查内核对象的状态,然后返回,不会等待。
其他正整数值表示等待的毫秒数。如果在指定的时间内对象的状态没有发生变化,函数会返回一个值,表示等待超时。
示例如下:
#include <iostream>
#include <windows.h>
using namespace std;DWORD WINAPI myProThread(PVOID lp)
{//ExitThread(0); 强制终止线程Sleep(5000); //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒return 0;
}int main()
{DWORD id = 0;HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);DWORD result = WaitForSingleObject(handle, 1); //这里是设定等待线程1毫秒,为了测定超时if (result == WAIT_OBJECT_0){// 线程结束,可以继续处理cout << "线程结束" << endl;}else if (result == WAIT_TIMEOUT){// 超时,可以采取相应的措施cout << "超时了" << endl;}else if (result == WAIT_FAILED){// 函数调用失败,可以通过 GetLastError() 获取错误信息DWORD dwError = GetLastError();cout << "线程错误代码为:" << dwError << endl;}cout << "该线程的ID是:" << id << endl;CloseHandle(handle); //关闭线程句柄return 0;
}// 等待线程结束

2.ExitThread()函数:
ExitThread 函数可以用于在线程函数内部直接退出线程。但是需要注意,使用此函数会终止线程的执行,不会调用线程的析构函数,也不会释放线程所占用的资源。这可能会导致资源泄漏或程序的不稳定性。
只能在线程内使用,终止该线程
示例如下:
代码:
#include <iostream>
#include <windows.h>
using namespace std;DWORD WINAPI myProThread(PVOID lp)
{ExitThread(0); //强制终止线程Sleep(5000); //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒return 0;
}int main()
{DWORD id = 0;HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);DWORD result = WaitForSingleObject(handle, 1); //这里是设定等待线程1毫秒,为了测定超时if (result == WAIT_OBJECT_0){// 线程结束,可以继续处理cout << "线程结束" << endl;}else if (result == WAIT_TIMEOUT){// 超时,可以采取相应的措施cout << "超时了" << endl;}else if (result == WAIT_FAILED){// 函数调用失败,可以通过 GetLastError() 获取错误信息DWORD dwError = GetLastError();cout << "线程错误代码为:" << dwError << endl;}cout << "该线程的ID是:" << id << endl;CloseHandle(handle); //关闭线程句柄return 0;
}// 等待线程结束
运行结果:

3.TerminateThread()函数:
TerminateThread 函数可以用来强制终止一个线程。然而,这个函数不安全,因为它会立即终止线程的执行,而不管线程正在做什么。这可能会导致未释放的资源,不稳定的状态,以及可能影响整个进程的问题。推荐避免使用这个函数。
可以在线程外使用,终止指定线程
这里不做示例,只提供函数如何使用:
TerminateThread(hThread, 0); //第一个参数是线程句柄,第二个参数是退出码(无意义)
4.CloseHandle()函数:
如果你有线程的句柄,可以使用 CloseHandle 函数来关闭线程句柄。这不会终止线程,但会释放句柄所占用的资源。这个函数的主要作用是清理句柄,而不是终止线程。
注:在关闭线程句柄之前,通常应该确保线程已经退出或者至少没有使用线程句柄引用了线程。
5.正常return 0;
不做赘述。
三、线程的恢复与挂起
1.挂起线程:
PS:下列代码输出求挂起数时,加了1。
①SuspendedThread()函数:
参数为线程句柄,返回值为先前的挂起数(即调用该函数次数)
示例如下:
代码:
#include <iostream>
#include <windows.h>
using namespace std;DWORD WINAPI myProThread(PVOID lp)
{//ExitThread(0); //强制终止线程Sleep(5000); //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒return 0;
}int main()
{DWORD id = 0;HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id); //第五个参数表示创建完成时挂起线程cout << "该线程的ID是:" << id << endl;DWORD result = WaitForSingleObject(handle, 3000); //这里是设定等待线程1毫秒,为了测定超时// 挂起线程DWORD suspendCount = SuspendThread(handle);cout << "初始挂起数为:" << suspendCount + 1 << endl;// 检查是否成功挂起线程if (suspendCount != -1) {cout << "线程已挂起" << endl;} else {cerr << "无法挂起线程" << endl;}if (result == WAIT_OBJECT_0){// 线程结束,可以继续处理cout << "线程结束" << endl;}else if (result == WAIT_TIMEOUT){// 超时,可以采取相应的措施cout << "超时了" << endl;}else if (result == WAIT_FAILED){// 函数调用失败,可以通过 GetLastError() 获取错误信息DWORD dwError = GetLastError();cout << "线程错误代码为:" << dwError << endl;}CloseHandle(handle); //关闭线程句柄return 0;
}
结果:

②CreateThread()的第五个参数设为CEREATE_SUSPENDED
代码同上,只是在创建线程时,把第五个参数设为CEREATE_SUSPENDED了
结果:

四、线程的优先级
在 Windows 下,C++ 程序可以使用线程库(Thread Library)来创建和管理线程。在 Windows 中,线程优先级用于确定操作系统在有多个线程要执行时,如何进行线程调度。Windows 提供了一组函数和常量来设置和获取线程的优先级。以下是关于 Windows 下 C++ 线程优先级的重要信息:
1. **线程优先级范围:** 在 Windows 系统中,线程的优先级范围通常是从 0(最低优先级)到 31(最高优先级)。
2. **默认优先级:** 当创建一个新线程时,它默认会继承创建它的线程的优先级。
3. **设置线程优先级:** 可以使用 `SetThreadPriority` 函数来设置线程的优先级。该函数的原型如下:
BOOL SetThreadPriority(
HANDLE hThread,
int nPriority
);- `hThread`:要设置优先级的线程句柄。
- `nPriority`:要设置的优先级,可以是以下常量之一:
- `THREAD_PRIORITY_IDLE`
- `THREAD_PRIORITY_LOWEST`
- `THREAD_PRIORITY_BELOW_NORMAL`
- `THREAD_PRIORITY_NORMAL`
- `THREAD_PRIORITY_ABOVE_NORMAL`
- `THREAD_PRIORITY_HIGHEST`
- `THREAD_PRIORITY_TIME_CRITICAL`
4. **获取线程优先级:** 可以使用 `GetThreadPriority` 函数来获取线程的当前优先级。该函数的原型如下:
int GetThreadPriority(
HANDLE hThread
);
- `hThread`:要查询优先级的线程句柄。
需要注意的是,虽然可以通过设置线程的优先级来影响线程的调度,但是过度使用优先级可能会导致问题,如饥饿、不公平调度等。正确地使用同步机制和合适的线程优先级,以确保程序的稳定性和可预测性,是良好的多线程编程实践的一部分。
在实际开发中,除非你有明确的需求,一般不建议频繁地改变线程的优先级,而是让操作系统自行管理线程调度,以确保整个系统的平稳运行。
相关文章:
创建线程、线程的挂起与恢复、线程的优先级与终止线程
目录 一、创建线程 CreateThread函数: 下面是示例: 编辑 ThreadProc函数解释: DWORD的本质是 unsigned long PVOID的本质是 void* 二、线程的终止 1.WaitForSingleObject()函数: 示例如下: 2.ExitThread()函…...
[保研/考研机试] KY180 堆栈的使用 吉林大学复试上机题 C++实现
题目链接: 堆栈的使用_牛客题霸_牛客网 描述 堆栈是一种基本的数据结构。堆栈具有两种基本操作方式,push 和 pop。其中 push一个值会将其压入栈顶,而 pop 则会将栈顶的值弹出。现在我们就来验证一下堆栈的使用。 输入描述: 对于…...
【AI理论学习】手把手推导扩散模型:Diffusion Models(DDPM)
手把手推导扩散模型:Diffusion Models(DDPM) DDPM理论回顾前置知识过程详解Forward ProcessReverse Process DDPM算法伪代码训练部分采样部分 总结一下 参考链接 在这篇博客文章中,我们将深入研究 去噪扩散概率模型(也称为 DDPM&…...
智能汽车 论坛收集
1.焉知汽车 焉知汽车 2.智能汽车俱乐部 智能汽车资源网 - 智能表面,智能内饰,新能源汽车,HMI,人车交互,智能车灯,车用材料 3.行业报告 发现报告 - 专业研报平台丨收录海量行业报告、券商研报丨免费分享…...
24届近5年南京航空航天大学自动化考研院校分析
今天给大家带来的是南京航空航天大学控制考研分析 满满干货~还不快快点赞收藏 一、南京航空航天大学 学校简介 南京航空航天大学创建于1952年10月,是新中国自己创办的第一批航空高等院校之一。1978年被国务院确定为全国重点大学;1981年经…...
Linux Day07
一、僵死进程 1.1僵死进程产生的原因 子进程先于父进程结束, 而父进程没有获取子进程退出码,释放子进程占用的资源,此时子进程将成为一个僵死进程。 在第一个框这里时父进程子进程都没有结束,显示其pid 父进程是2349,子进程是235…...
数字化管理,让MRO工业品更高效
MRO商品数字化是将MRO商品的采购、库存及记录过程进行数字化管理,以提高MRO商品的效率和可控性。MRO(Maintenance, Repair and Operations)一般用于维修、保养及日常运营工作中,包括五金工具、紧固件、精加工刀具、备品备件、切屑…...
layui中渲染table表格
页面布局 可直接根据文档要求去写 table 组件(这个不重要) <table lay-filter"SyDictTable" id"SyDictTable" lay-data"{id: SyDictTable}"></table>Js 重要的是去修改JS里面的东西,比如&#…...
2023-08-10LeetCode每日一题(下降路径最小和 II)
2023-08-10每日一题 一、题目编号 1289. 下降路径最小和 II二、题目链接 点击跳转到题目位置 三、题目描述 给你一个 n x n 整数矩阵 grid ,请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为:从 grid 数组中的每一行选择一个数…...
网络基础2(HTTP,HTTPS,传输层协议详解)
再谈协议 在之前利用套接字进行通信的时候,我们都是利用 “字符串” 进行流式的发送接收,但是我们平常进行交流通信肯定不能只是简单的发送字符串。 比如我们用QQ进行聊天,我们不仅需要得到对方发送的消息,还要知道对方的昵称&…...
Java实现籍贯级联选择器
在工作中要求写一个籍贯的级联选择器,记录一下自己写这个级联选择器的过程,因为自己才刚开始工作,有很多地方都没有考虑的很清楚,希望各位大佬能给出建议。 一、需求 A:正常的23个省,籍贯由“省区/县/市”组成…...
每日一学——OSI参考模型
OSI参考模型(Open Systems Interconnection Reference Model)是国际标准化组织(ISO)制定的一个网络通信协议的概念框架。它将网络通信划分为七个层次,每个层次负责不同的功能和任务,从物理层到应用层依次为…...
虚幻5中Lumen提供哪些功能以及如何工作的
虚幻引擎 5 中的 Lumen 是一个完全动态的全局照明和反射系统。它可以在虚幻引擎 5 中使用,因此创作者无需自行设置。它是为下一代控制台和建筑可视化等高端可视化而设计的。那么它提供了哪些功能以及如何工作? 全局照明 当光离开光源时,它会…...
Linux C 语言 mosquitto 方式 MQTT 发布消息
1 说明 采用 mosquitto 库,实现对主题发布消息。 其中服务器有做限制,需要对应的 cilent id ,cafile 、certfile 、keyfile 等配置 2 开发环境 采用ubuntu 直接编译调试 安装mosquitto 库 sudo apt install libmosquitto-dev sudo apt-ge…...
利用NtDuplicateObject进行Dump
前言 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习) 这是国外老哥2020年提出的一种蛮有意思的思路。 我们先来看看大致的思路是…...
【快应用】list组件如何区分滑动的方向?
【关键词】 list组件、滑动方向、scroll 【问题背景】 有cp反馈list这个组件在使用的时候,不知道如何区分它是上滑还是下滑。 【问题分析】 list组件除了通用事件之外,还提供了scroll、scrollbottom、scrolltop、scrollend、scrolltouchup事件&#x…...
【深入了解pytorch】PyTorch扩展:如何使用PyTorch的扩展功能
【深入了解pytorch】PyTorch扩展:如何使用PyTorch的扩展功能 PyTorch扩展:展示如何使用PyTorch的扩展功能1. 自定义损失函数2. 自定义数据加载器3. 自定义优化器总结PyTorch扩展:展示如何使用PyTorch的扩展功能 PyTorch作为一个开源的深度学习框架,在研究和应用领域广受欢…...
Vue3——如何实现页面访问拦截
在现代的Web开发中,页面访问拦截是一个非常常见的需求。通过拦截页面访问,我们可以控制用户在访问特定页面之前需要满足的条件,比如登录状态、权限等。Vue是一个非常流行的JavaScript框架,它提供了许多强大的工具和功能࿰…...
nginx配置gzip
在 Nginx 中启用 Gzip 压缩可以大幅减少传输内容的大小,从而加快网页加载速度。 打开 Nginx 的配置文件,通常是 /etc/nginx/nginx.conf 或者 /etc/nginx/conf.d/default.conf。找到 http 配置块,在其中添加以下代码来开启 Gzip 压缩ÿ…...
ExtJS教程_编程入门自学教程_菜鸟教程-免费教程分享
教程简介 Ext JS是一个流行的JavaScript框架,它为使用跨浏览器功能构建Web应用程序提供了丰富的UI。 Ext JS基本上用于创建桌面应用程序它支持所有现代浏览器,如IE6 ,FF,Chrome,safari 6 等。Ext JS基于MVC / MVVM架构…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

