当前位置: 首页 > news >正文

创建线程、线程的挂起与恢复、线程的优先级与终止线程

目录

一、创建线程

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_ptrstd::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函数&#xff1a; 下面是示例&#xff1a; ​编辑 ThreadProc函数解释&#xff1a; DWORD的本质是 unsigned long PVOID的本质是 void* 二、线程的终止 1.WaitForSingleObject()函数&#xff1a; 示例如下&#xff1a; 2.ExitThread()函…...

[保研/考研机试] KY180 堆栈的使用 吉林大学复试上机题 C++实现

题目链接&#xff1a; 堆栈的使用_牛客题霸_牛客网 描述 堆栈是一种基本的数据结构。堆栈具有两种基本操作方式&#xff0c;push 和 pop。其中 push一个值会将其压入栈顶&#xff0c;而 pop 则会将栈顶的值弹出。现在我们就来验证一下堆栈的使用。 输入描述&#xff1a; 对于…...

【AI理论学习】手把手推导扩散模型:Diffusion Models(DDPM)

手把手推导扩散模型&#xff1a;Diffusion Models&#xff08;DDPM&#xff09; DDPM理论回顾前置知识过程详解Forward ProcessReverse Process DDPM算法伪代码训练部分采样部分 总结一下 参考链接 在这篇博客文章中&#xff0c;我们将深入研究 去噪扩散概率模型(也称为 DDPM&…...

智能汽车 论坛收集

1.焉知汽车 焉知汽车 2.智能汽车俱乐部 智能汽车资源网 - 智能表面&#xff0c;智能内饰&#xff0c;新能源汽车&#xff0c;HMI&#xff0c;人车交互&#xff0c;智能车灯&#xff0c;车用材料 3.行业报告 发现报告 - 专业研报平台丨收录海量行业报告、券商研报丨免费分享…...

24届近5年南京航空航天大学自动化考研院校分析

今天给大家带来的是南京航空航天大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、南京航空航天大学 学校简介 南京航空航天大学创建于1952年10月&#xff0c;是新中国自己创办的第一批航空高等院校之一。1978年被国务院确定为全国重点大学&#xff1b;1981年经…...

Linux Day07

一、僵死进程 1.1僵死进程产生的原因 子进程先于父进程结束, 而父进程没有获取子进程退出码&#xff0c;释放子进程占用的资源&#xff0c;此时子进程将成为一个僵死进程。 在第一个框这里时父进程子进程都没有结束&#xff0c;显示其pid 父进程是2349&#xff0c;子进程是235…...

数字化管理,让MRO工业品更高效

MRO商品数字化是将MRO商品的采购、库存及记录过程进行数字化管理&#xff0c;以提高MRO商品的效率和可控性。MRO&#xff08;Maintenance, Repair and Operations&#xff09;一般用于维修、保养及日常运营工作中&#xff0c;包括五金工具、紧固件、精加工刀具、备品备件、切屑…...

layui中渲染table表格

页面布局 可直接根据文档要求去写 table 组件&#xff08;这个不重要&#xff09; <table lay-filter"SyDictTable" id"SyDictTable" lay-data"{id: SyDictTable}"></table>Js 重要的是去修改JS里面的东西&#xff0c;比如&#…...

2023-08-10LeetCode每日一题(下降路径最小和 II)

2023-08-10每日一题 一、题目编号 1289. 下降路径最小和 II二、题目链接 点击跳转到题目位置 三、题目描述 给你一个 n x n 整数矩阵 grid &#xff0c;请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为&#xff1a;从 grid 数组中的每一行选择一个数…...

网络基础2(HTTP,HTTPS,传输层协议详解)

再谈协议 在之前利用套接字进行通信的时候&#xff0c;我们都是利用 “字符串” 进行流式的发送接收&#xff0c;但是我们平常进行交流通信肯定不能只是简单的发送字符串。 比如我们用QQ进行聊天&#xff0c;我们不仅需要得到对方发送的消息&#xff0c;还要知道对方的昵称&…...

Java实现籍贯级联选择器

在工作中要求写一个籍贯的级联选择器&#xff0c;记录一下自己写这个级联选择器的过程&#xff0c;因为自己才刚开始工作&#xff0c;有很多地方都没有考虑的很清楚&#xff0c;希望各位大佬能给出建议。 一、需求 A:正常的23个省&#xff0c;籍贯由“省区/县/市”组成&#xf…...

每日一学——OSI参考模型

OSI参考模型&#xff08;Open Systems Interconnection Reference Model&#xff09;是国际标准化组织&#xff08;ISO&#xff09;制定的一个网络通信协议的概念框架。它将网络通信划分为七个层次&#xff0c;每个层次负责不同的功能和任务&#xff0c;从物理层到应用层依次为…...

虚幻5中Lumen提供哪些功能以及如何工作的

虚幻引擎 5 中的 Lumen 是一个完全动态的全局照明和反射系统。它可以在虚幻引擎 5 中使用&#xff0c;因此创作者无需自行设置。它是为下一代控制台和建筑可视化等高端可视化而设计的。那么它提供了哪些功能以及如何工作&#xff1f; 全局照明 当光离开光源时&#xff0c;它会…...

Linux C 语言 mosquitto 方式 MQTT 发布消息

1 说明 采用 mosquitto 库&#xff0c;实现对主题发布消息。 其中服务器有做限制&#xff0c;需要对应的 cilent id &#xff0c;cafile 、certfile 、keyfile 等配置 2 开发环境 采用ubuntu 直接编译调试 安装mosquitto 库 sudo apt install libmosquitto-dev sudo apt-ge…...

利用NtDuplicateObject进行Dump

前言 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。&#xff08;本文仅用于交流学习&#xff09; 这是国外老哥2020年提出的一种蛮有意思的思路。 我们先来看看大致的思路是…...

【快应用】list组件如何区分滑动的方向?

【关键词】 list组件、滑动方向、scroll 【问题背景】 有cp反馈list这个组件在使用的时候&#xff0c;不知道如何区分它是上滑还是下滑。 【问题分析】 list组件除了通用事件之外&#xff0c;还提供了scroll、scrollbottom、scrolltop、scrollend、scrolltouchup事件&#x…...

【深入了解pytorch】PyTorch扩展:如何使用PyTorch的扩展功能

【深入了解pytorch】PyTorch扩展:如何使用PyTorch的扩展功能 PyTorch扩展:展示如何使用PyTorch的扩展功能1. 自定义损失函数2. 自定义数据加载器3. 自定义优化器总结PyTorch扩展:展示如何使用PyTorch的扩展功能 PyTorch作为一个开源的深度学习框架,在研究和应用领域广受欢…...

Vue3——如何实现页面访问拦截

在现代的Web开发中&#xff0c;页面访问拦截是一个非常常见的需求。通过拦截页面访问&#xff0c;我们可以控制用户在访问特定页面之前需要满足的条件&#xff0c;比如登录状态、权限等。Vue是一个非常流行的JavaScript框架&#xff0c;它提供了许多强大的工具和功能&#xff0…...

nginx配置gzip

在 Nginx 中启用 Gzip 压缩可以大幅减少传输内容的大小&#xff0c;从而加快网页加载速度。 打开 Nginx 的配置文件&#xff0c;通常是 /etc/nginx/nginx.conf 或者 /etc/nginx/conf.d/default.conf。找到 http 配置块&#xff0c;在其中添加以下代码来开启 Gzip 压缩&#xff…...

ExtJS教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Ext JS是一个流行的JavaScript框架&#xff0c;它为使用跨浏览器功能构建Web应用程序提供了丰富的UI。 Ext JS基本上用于创建桌面应用程序它支持所有现代浏览器&#xff0c;如IE6 &#xff0c;FF&#xff0c;Chrome&#xff0c;safari 6 等。Ext JS基于MVC / MVVM架构…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...