线程函数传 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 项目中希望读者能理解并熟练掌握它。

相关新闻

最新新闻

基于微信小程序与Spring Boot的宠物美容预约系统实战开发

基于微信小程序与Spring Boot的宠物美容预约系统实战开发

宠物美容预约是线下宠物门店非常典型的业务场景:客户需要提前挑选服务项目、选择门店和美容师、确定到店时间,门店则需要根据人力排班安排接待。传统的人工预约方式容易出现信息遗漏、时间段冲突、客户到店等待时间过长等问题。本文以“基于微信小程序的…

2026/8/26 7:35:49
C++函数设计四层跃迁:从语法正确到工程可靠

C++函数设计四层跃迁:从语法正确到工程可靠

1. 这不是“写个函数”那么简单:C实验1的真实定位与新手常见误区 “C实验1:C函数程序设计”——看到这个标题,很多刚接触C的同学第一反应是:“不就是写几个函数吗? int add(int a, int b) { return a b; } &#xf…

2026/8/26 7:35:49
天工Omni 45.66秒夺冠背后:人形机器人运动控制与芯片架构解析

天工Omni 45.66秒夺冠背后:人形机器人运动控制与芯片架构解析

天工 Omni 用 45.66 秒跑完 400 米的小型组决赛,这个成绩在普通人眼里可能只是“一台机器人跑得挺快”,但在做机器人的工程师眼里,这背后牵扯的是运动控制、足底力感知、实时算力分配、芯片选型、仿真迁移这一整套系统工程。最近“人形机器人…

2026/8/26 7:35:49
基于深度学习的图像去噪:CNN与残差学习全解析

基于深度学习的图像去噪:CNN与残差学习全解析

简介:图像去噪是计算机视觉长期关注的基础问题,旨在从含噪观测中恢复干净图像。传统滤波算法在强噪声下易导致纹理模糊,而卷积神经网络(CNN)凭借数据驱动的特征学习能力,结合残差学习策略,让网络…

2026/8/26 7:35:49
CNN图像去噪实战:DnCNN残差学习与训练全流程解析

CNN图像去噪实战:DnCNN残差学习与训练全流程解析

简介:图像去噪是底层视觉中的经典任务,核心目标是从带噪观测中恢复干净图像。传统方法依赖手工先验,而深度学习通过卷积神经网络自动学习噪声分布与图像结构之间的映射关系,为图像复原提供了更强大的工具。DnCNN作为代表性CNN去噪…

2026/8/26 7:35:49
LLM实操入门:从ChatGPT到本地部署的避坑指南

LLM实操入门:从ChatGPT到本地部署的避坑指南

1. 这不是“科普文”,而是一份LLM实操者的手写笔记 我第一次在终端里敲出 python -c "print(hello world)" 时,根本没想过十年后会花整整三周时间,只为搞懂为什么一个模型输出的句子末尾总多一个空格。今天聊的这个标题——“Cha…

2026/8/26 7:30:48