C++最基本的线程管理(完整源码)

news/2024/4/28 18:51:04

初级代码游戏的专栏介绍与文章目录-CSDN博客

        讲起编程理论天花乱坠,现实却跟山顶洞人一样。

目录

一、问题

二、跟踪线程创建

三、多线程的一般原则

四、相关技术点

4.1 CreateThread

4.2 CloseHandle

4.3 GetExitCodeThread

4.4 TerminateThread


一、问题

        前两年维护一些老程序,发现这么用线程的:

HANDLE hThread=CreateThread(。。。。。。);
CloseHandle(hThread);		

        就是这么潇洒!

        是不是线程里面有高级机制控制啊?我啃了源代码啊,没有,真的没有。

        为啥啃源代码啊,随机BUG了呗。虽然不确定BUG怎么引起的,先解决不受控的线程总是没错的。

二、跟踪线程创建

        所以要记录有哪些线程、检测线程状态,为此写了一个这么一个类:

//线程管理,目前主要用来在结束时先关闭子线程
class CThreadManager
{
private:struct struct_thread_info{HANDLE hThread;string file;//创建此线程的代码位置int line;//创建此线程的代码位置};vector<struct_thread_info > m_managered_threads;void ClearFinishedThread(bool stop);
public:void AddThreadHandle(HANDLE h, char const* file, int line){ClearFinishedThread(false);struct_thread_info tmp;tmp.hThread = h;tmp.file = file;tmp.line = line;m_managered_threads.push_back(tmp);}void StopAllThread();
};
extern CThreadManager g_CThreadManager;
#define AddManageredThread(h) g_CThreadManager.AddThreadHandle((h),__FILE__,__LINE__)

        结构struct_thread_info记录线程句柄和创建位置,方便找到相关代码。

        宏AddManageredThread(h)简化了调用方法。

        全局对象和两个成员函数:

CThreadManager g_CThreadManager;void CThreadManager::ClearFinishedThread(bool stop)
{for (int i = m_managered_threads.size() - 1; i >= 0; --i){DWORD exitcode;if (!GetExitCodeThread(m_managered_threads[i].hThread, &exitcode)){MessageBox(NULL, "GetExitCodeThread失败", "出错", 0);return;}if (STILL_ACTIVE != exitcode){CloseHandle(m_managered_threads[i].hThread);m_managered_threads.erase(m_managered_threads.begin() + i);}else{if (stop){TerminateThread(m_managered_threads[i].hThread, 1);CloseHandle(m_managered_threads[i].hThread);m_managered_threads.erase(m_managered_threads.begin() + i);}}}
}void CThreadManager::StopAllThread()
{ClearFinishedThread(true);
}

        调用的时候用AddManageredThread代替CloseHandle就可以了,程序退出的时候先执行StopAllThread结束所有子线程,免得因为退出的先后顺序出异常。

        AddManageredThread的特点是自动回收已经结束的子线程(所以在程序结束前最多存在一个已经结束而未回收的线程)。GetExitCodeThread获取子线程结束状态。

        上面的代码在结束时直接强制终止了子线程,安全的方法是设置全局变量,所有子线程不时检测全局变量状态,实现受控的退出。对于控制线程退出而言,全局变量已经足够好了,其它机制,比如信号、消息,只会带来不必要的复杂度而不会减轻任何编码量。

        CloseHandle的特点是让子线程结束后自动回收,但是不知道子线程什么时候结束嘛,程序结束前难免手动清理一些资源,而子线程却在使用这些资源,这不就BUG了嘛。

三、多线程的一般原则

        多线程程序最基本的原则就是子线程应该是受管理的,最起码的,就像上面写的类一样,要把创建和停止管理起来,在程序退出的时候先关闭所有子线程,再退出主程序。

        线程的交互尽量简单,尽量用一个独立的交互区来操作,不要让每个线程都可以随意使用整个程序的数据,数据保护很难做。

        线程里面不要再创建线程,很难管理。

        从基本完成一个程序到解决随机BUG很漫长。学会使用CreateThread不算什么,功夫都在自己的代码逻辑里。

四、相关技术点

4.1 CreateThread

HANDLE CreateThread([in, optional]  LPSECURITY_ATTRIBUTES   lpThreadAttributes,[in]            SIZE_T                  dwStackSize,[in]            LPTHREAD_START_ROUTINE  lpStartAddress,[in, optional]  __drv_aliasesMem LPVOID lpParameter,[in]            DWORD                   dwCreationFlags,[out, optional] LPDWORD                 lpThreadId
);

        创建线程,参数很多不过大部分都可以不用。

4.2 CloseHandle

BOOL CloseHandle([in] HANDLE hObject
);

        关闭句柄。这个API的意思并不是删除句柄代表的资源,只是表示结束对资源的使用。对于线程而言,这个操作并不表示结束线程,而是表示让它运行完了自己结束就好了。

        线程的访问计数和别的资源不一样,线程一启动计数就是2,CloseHandle只会减少1,所以CloseHandle之后线程还有计数1,仍是有效的。 

4.3 GetExitCodeThread

BOOL GetExitCodeThread([in]  HANDLE  hThread,[out] LPDWORD lpExitCode
);

        获取线程退出状态。如果线程没有退出,要自己想办法,直接杀死线程太粗暴了。

4.4 TerminateThread

BOOL TerminateThread([in, out] HANDLE hThread,[in]      DWORD  dwExitCode
);

         杀死线程,很不好。dwExitCode设置线程返回值——你自己杀死的你不知道咋回事吗?这个返回值是给调用GetExitCodeThread的人看的,不是给自己看的。

        以上代码是以win7+vs2010为目标的,可在win10、win11上运行。

(这里是文档结束)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

链动2+1模式 完全合法合规 不存在传销问题!!

在商业经营中&#xff0c;营销策略的巧妙运用对于提升产品销量和扩大品牌影响力至关重要。然而&#xff0c;企业在制定和执行营销策略时&#xff0c;必须严格遵循法律法规&#xff0c;以免陷入法律风险。本文将着重探讨链动21模式的法律要素&#xff0c;以论证其合规性。 一、链…

npm i安装依赖报错,但是cnpm i 却安装成功

问题描述&#xff1a;在a项目中npm i 安装依赖时发生以上报错&#xff0c;但是cnpm i 却成功&#xff0c;而且在其他项目中npm i 安装其他项目依赖也能成功.... 解决办法&#xff1a;删除项目中package-lock.json文件后再npm i 即可

Redis入门到实战-第三弹

Redis入门到实战 Redis数据类型官网地址Redis概述Redis数据类型介绍更新计划 Redis数据类型 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#…

nodejs+vue高校门诊管理系统python-flask-django-php

相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低高校门诊的运营人员成本&#xff0c;实现了高校门诊管理的标准化、制度化、程序化的管理&#xff0c;有效地防止了高校门诊管理的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时…

AV1:帧内预测(一)

​VP9支持10种帧内预测模式&#xff0c;包括8种角度模式和非角度模式DC、TM(True Motion)模式&#xff0c;AV1在其基础上进一步扩展&#xff0c;AV1帧内预测角度模式更细化&#xff0c;同时新增了部分非角度模式。 扩展的角度模式 AV1在VP9角度模式的基础上进一步扩展&#xf…

4G/5G视频记录仪_联发科MTK6765平台智能记录仪方案

视频记录仪主板采用了联发科MT6765芯片&#xff0c;该芯片采用12nm FinFET制程工艺&#xff0c;8*Cortex-A53架构&#xff0c;搭载安卓11.0/13.0系统&#xff0c;主频最高达2.3GHz&#xff0c;待机功耗可低至5ma&#xff0c;并具有快速数据传输能力。配备了2.4英寸高清触摸显示…