线程函数传 C++ 类实例指针惯用法 线程函数传 C 类实例指针惯用法前面的章节介绍了除了 C 11 的线程库提供了的std::thread类对线程函数签名没有特殊要求外无论是 Linux 还是 Windows 的线程函数的签名都必须是指定的格式即参数和返回值必须是规定的形式。如果使用 C 面向对象的方式对线程函数进行封装那么线程函数就不能是类的实例方法即必须是类的静态方法。那么为什么不能是类的实例方法呢我们以 Linux 的线程函数签名为例void threadFunc(void* arg);假设我们将线程的基本功能封装到一个Thread类中部分代码如下class Thread { public: Thread(); ~Thread(); void start(); void stop(); void threadFunc(void* arg); };由于threadFunc是一个类实例方法无论是类的实例方法还是静态方法C 编译器在编译时都会将这些函数”翻译“成全局函数即去掉类的域限制。对于实例方法为了保证类方法的正常功能C 编译器在翻译时会将类的实例对象地址也就是this指针作为第一个参数传递给该方法也就是说翻译后的threadFunc的签名变成了如下形式伪代码void threadFunc(Thread* this, void* arg);这样的话就不符合线程函数签名要求了。因此如果一个线程函数作为类方法只能是静态方法而不能是实例方法。当然如果是使用 C 11 的 **std::thread **类就没有这个限制即使类成员函数是类的实例方法也可以但是必须显式地将线程函数所属的类对象实例指针在类的内部就是this指针作为构造函数参数传递给std::thread还是需要传递类的 this 指针这在本质上是一样的代码实例如下#include thread #include memory #include stdio.h class Thread { public: Thread() { } ~Thread() { } void Start() { m_stopped false; //threadFunc是类的非静态方法所以作为线程函数第一个参数必须传递类实例地址即this指针 m_spThread.reset(new std::thread(Thread::threadFunc, this, 8888, 9999)); } void Stop() { m_stopped true; if (m_spThread) { if (m_spThread-joinable()) m_spThread-join(); } } private: void threadFunc(int arg1, int arg2) { while (!m_stopped) { printf(Thread function use instance method.\n); } } private: std::shared_ptrstd::thread m_spThread; bool m_stopped; }; int main() { Thread mythread; mythread.Start(); while (true) { //权宜之计让主线程不要提前退出 } return 0; }上述代码中使用了 C 11 新增的智能指针std::shared_ptr类来包裹了一下 new 出来的std::thread对象这样我们就不需要自己手动 delete 这个std::thread对象了。综上所述如果不使用 C 11 的语法那么线程函数只能作为类的静态方法且函数签名必须按规定的签名格式来。如果是类的静态方法那么就没法访问类的实例方法了为了解决这个问题我们在实际开发中往往会在创建线程时将当前对象的地址this指针传递给线程函数然后在线程函数中将该指针转换成原来的类实例再通过这个实例就可以访问类的所有方法了。代码示例如下.h文件代码如下/** * Thread.h */ #ifdef WIN32 //#include windows.h typedef HANDLE THREAD_HANDLE ; #else //#include pthread.h typedef pthread_t THREAD_HANDLE ; #endif /**定义了一个线程对象 */ class CThread { public: /**构造函数 */ CThread(); /**析构函数 */ virtual ~CThread(); /**创建一个线程 * return true:创建成功 false:创建失败 */ virtual bool Create(); /**获得本线程对象存储的线程句柄 * return 本线程对象存储的线程句柄线程句柄 */ THREAD_HANDLE GetHandle(); /**线程睡眠seconds秒 * param seconds 睡眠秒数 */ void OSSleep(int nSeconds); void SleepMs(int nMilliseconds); bool Join(); bool IsCurrentThread(); void ExitThread(); private: #ifdef WIN32 static DWORD WINAPI _ThreadEntry(LPVOID pParam); #else static void* _ThreadEntry(void* pParam); #endif /**虚函数子类可做一些实例化工作 * return true:创建成功 false:创建失败 */ virtual bool InitInstance(); /**虚函数子类清楚实例 */ virtual void ExitInstance(); /**线程开始运行纯虚函数子类必须继承实现 */ virtual void Run() 0; private: THREAD_HANDLE m_hThread; /** 线程句柄 */ DWORD m_IDThread; };.cpp文件如下/** * Thread.cpp */ #include Thread.h #ifdef WIN32 DWORD WINAPI CThread::_ThreadEntry(LPVOID pParam) #else void* CThread::_ThreadEntry(void* pParam) #endif { CThread *pThread (CThread *)pParam; if(pThread-InitInstance()) { pThread-Run(); } pThread-ExitInstance(); return NULL; } CThread::CThread() { m_hThread (THREAD_HANDLE)0; m_IDThread 0; } CThread::~CThread() { } bool CThread::Create() { if (m_hThread ! (THREAD_HANDLE)0) { return true; } bool ret true; #ifdef WIN32 m_hThread ::CreateThread(NULL,0,_ThreadEntry,this,0,m_IDThread); if(m_hThreadNULL) { ret false; } #else ret (::pthread_create(m_hThread,NULL,_ThreadEntry , this) 0); #endif return ret; } bool CThread::InitInstance() { return true; } void CThread::ExitInstance() { } void CThread::OSSleep(int seconds) { #ifdef WIN32 ::Sleep(seconds*1000); #else ::sleep(seconds); #endif } void CThread::SleepMs(int nMilliseconds) { #ifdef WIN32 ::Sleep(nMilliseconds); #else ::usleep(nMilliseconds); #endif } bool CThread::IsCurrentThread() { #ifdef WIN32 return ::GetCurrentThreadId() m_IDThread; #else return ::pthread_self() m_hThread; #endif } bool CThread::Join() { THREAD_HANDLE hThread GetHandle(); if(hThread (THREAD_HANDLE)0) { return true; } #ifdef WIN32 return (WaitForSingleObject(hThread,INFINITE) ! 0); #else return (pthread_join(hThread, NULL) 0); #endif } void CThread::ExitThread() { #ifdef WIN32 ::ExitThread(0); #else #endif }上述代码CThread类封装了一个线程的常用的操作使用宏WIN32来分别实现了 Windows 和 Linux 两个操作系统平台的线程操作。其中InitInstance和ExitInstance方法为虚函数在继承CThread的子类中可以改写这两个方法根据实际需要在线程函数正式业务逻辑前后做一些初始化和反初始化工作而纯虚接口Run方法必须改写改写成您的线程实际执行函数。在线程函数中通过在创建线程时调用CreateThread或pthread_create方法时将当前对象的this指针作为线程的函数的唯一参数传入这样在线程函数中可以通过线程函数参数得到对象的指针通过这个指针就可以自由访问类的实例方法了。这一技巧非常常用它广泛地用于各类开源 C 项目或者实际的商业 C 项目中希望读者能理解并熟练掌握它。

相关新闻

最新新闻

Sage勒索病毒应急响应实战:从入侵检测到系统加固全流程解析

Sage勒索病毒应急响应实战:从入侵检测到系统加固全流程解析

1. 事件背景与应急响应核心思路 那天早上,我接到一个紧急电话,电话那头是某公司IT主管,声音里带着明显的焦虑和疲惫。他说,公司内部的核心OA系统突然无法访问,首页变成了一堆乱码,更糟糕的是,市…

2026/7/3 13:08:14
LENA-R8与PIC24FJ256GB210的嵌入式通信与定位方案

LENA-R8与PIC24FJ256GB210的嵌入式通信与定位方案

1. LENA-R8与PIC24FJ256GB210的硬件组合解析 这套组合的核心价值在于将蜂窝通信与高精度定位能力集成到嵌入式系统中。LENA-R8是一款多模LTE Cat 1模块,支持14个LTE频段和4个GSM/GPRS频段,这意味着它能在全球绝大多数地区实现网络连接。其内置的u-blox G…

2026/7/3 13:08:14
WechatAPI:为什么响应式编程是高并发下的最优解?

WechatAPI:为什么响应式编程是高并发下的最优解?

在基于 WechatAPI(个人微信API)构建复杂的自动化社群管理系统或 AI 智能体编排系统时,开发者往往会面临一个核心矛盾:业务逻辑日益复杂,而底层的微信消息流却是一种不可控的、异步推送的事件源。当一个用户同时触发了“…

2026/7/3 13:08:14
如何高效使用SMAPI:星露谷物语模组加载完全指南

如何高效使用SMAPI:星露谷物语模组加载完全指南

如何高效使用SMAPI:星露谷物语模组加载完全指南 【免费下载链接】SMAPI The modding API for Stardew Valley. 项目地址: https://gitcode.com/gh_mirrors/smap/SMAPI SMAPI(Stardew Valley Modding API)是星露谷物语最强大的模组加载…

2026/7/3 13:08:14
终极免费方案:HunterPie让你的《怪物猎人:世界》狩猎体验全面升级

终极免费方案:HunterPie让你的《怪物猎人:世界》狩猎体验全面升级

终极免费方案:HunterPie让你的《怪物猎人:世界》狩猎体验全面升级 【免费下载链接】HunterPie-legacy A complete, modern and clean overlay with Discord Rich Presence integration for Monster Hunter: World. 项目地址: https://gitcode.com/gh_m…

2026/7/3 13:08:13
ICM-42688-P与PIC18F47K42在运动检测与工业监测中的应用

ICM-42688-P与PIC18F47K42在运动检测与工业监测中的应用

1. ICM-42688-P与PIC18F47K42的黄金组合解析 在机器人控制和工业监测领域,传感器与微控制器的选型直接决定了系统性能上限。ICM-42688-P这款6轴IMU(惯性测量单元)与PIC18F47K42微控制器的组合,正在成为高精度运动检测系统的标配方…

2026/7/3 13:03:13

周新闻

月新闻