C++ CreateThread函数如何传递this指针作为参数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ CreateThread函数如何传递this指针作为参数相关的知识,希望对你有一定的参考价值。

m_hThread = ::CreateThread(NULL, 0, CTcpServer::ThreadProc(), (void *)this, 0, &m_dwThread);

我在VS2008上编译的,它提示:error C2660: “CTcpServer::ThreadProc”: 函数不接受 0 个参数

this参数应该如何传送呢

CreateThread的第三个参数是函数地址,不是调用函数,所以请把第三个参数的后面的括号去掉,直接写成 。。。NULL, 0, CTcpServer::ThreadProc, (void*)。。。 参考技术A 1 template<class T>
2 void Call(T* ptr,void(T::*MenFn)())
3
4 (ptr->*MenFn)();
5

1 class MyClass
2
3 public:
4 void Call()
5
6
7
8 ;
9
10 MyClass cs;
11 Call(&cs,&MyCall::Call);

3. 虚拟继承的方法

1 class Base
2
3 public:
4 virtual void Call() = 0;
5 ;
6
7 class SubClass :public Base
8
9 public:
10 void Call()
11 ;
12
13 void Call(Base *ptr)
14
15 ptr->Call();
16
4.use boost.

1#include <boost/bind.hpp>
2#include <iostream>
3using namespace std;
4struct MyClass
5
6 void Print(const char* str)
7
8 cout<<"holle "<<str<<endl;
9
10;
11
12template<class _Fun>
13void CallBackFun(_Fun a,const char* str)
14
15 t(n);
16
17
18int main()
19
20 MyClass mc;
21 CallBackFun(boost::bind(boost::mem_fn(&MyClass::Print),&mc,_1),"world")
22 return 1;
23
24
5.使用静态成员函数或者联合体模拟之

1 union
2
3 void(G_CALL ParticleSystem::*PhysicsThreadFun)(void *arg);
4 ThreadFun f;
5 fn;
6 fn.PhysicsThreadFun = &ParticleSystem::PhysicsThreadFun;
7 thread_id = CreateThread(fn.f,&ps);
参考技术B 1. this指针的用处:
  一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。   例如,调用date.SetMonth(9) <===> SetMonth(&date, 9),this帮助完成了这一转换 .
2. this指针的使用:
一种情况就是,在类的非静态成员函数中返回类对象本身的时候,直接使用 return *this;另外一种情况是当参数与成员变量名相同时,如this->n = n (不能写成n = n)。
3. this指针程序示例:
this指针存在于类的成员函数中,指向被调用函数所在的类实例的地址。   根据以下程序来说明this指针
#include
class Point int x, y;
public:
Point(int a, int b) x=a; y=b;
void MovePoint( int a, int b) x+=a; y+=b;
void print() cout<<"x="<<x<<"y="<<y<<endl;
;
void main( )
Point point1( 10,10);
point1.MovePoint(2,2);
point1.print( );

当对象point1调用MovePoint(2,2)函数时,即将point1对象的地址传递给了this指针。
MovePoint函数的原型应该是 void MovePoint( Point *this, int a, int b);第一个参数是指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的。这样point1的地址传递给了this,所以在MovePoint函数中便显式的写成:
void MovePoint(int a, int b) this->x +=a; this-> y+= b;   即可以知道,point1调用该函数后,也就是point1的数据成员被调用并更新了值。   即该函数过程可写成 point1.x+= a; point1. y + = b;
参考技术C C++对于托管代码的封装一向不是很尽善尽美,从最初的static成员函数到MFC的消息映射表,及至ATL的thunk机制。真可谓花样百出、层出不穷了。究其原因,这乃是C++的this指针惹的祸,这个“祸害”也就是Borland的VCL是用Object PASCAL编写的,而C++ Buider只能提供VCL的动态链接之缘由了。
然而,我在不经意之间却获得了另一个封装的方法,完全脱离了static成员函数的一贯做法,并直接将非static成员函数指定为线程的托管代码——也许这听上去很神奇,其实不过尔尔,且听李马慢慢道来。
首先我将线程对象封装成一个纯虚基类ThreadObject,如下:
class ThreadObject

public:
virtual void Create() = 0;
void Wait()

WaitForSingleObject( m_hThread, INFINITE );
CloseHandle( m_hThread );

protected:
virtual DWORD WINAPI DoWork( void )

for ( int i = 0; i < 10; i++ )

Sleep( rand() % 1000 );
printf( "Thread X is running. ", m_dwThreadID );

return 0;

DWORD m_dwThreadID;
HANDLE m_hThread;
;

这个类简单地封装了线程对象的数据成员及工作函数,下面我将基于这个类使用C++的继承来实现两种不同的托管封装。
首先是通常使用的方法。这种方法使用了一个static成员函数作为线程的托管代码,在创建线程的时候将类的this指针传入作为线程参数,代码大致如下:
class MyThread1 : public ThreadObject

public:
void Create()

m_hThread = CreateThread( NULL, 0, MyThread1::m_ThreadProc, this, 0, &m_dwThreadID );

protected:
static DWORD WINAPI m_ThreadProc( LPVOID lpParam )

MyThread1 *pThis = (MyThread1 *)lpParam;
return pThis->DoWork();

;

在类构造函数中将此指针传递给 CreateThread 在线程过程中表现得很奇怪

【中文标题】在类构造函数中将此指针传递给 CreateThread 在线程过程中表现得很奇怪【英文标题】:Passing this pointer to CreateThread in class constructor behaves weird in thread procedure 【发布时间】:2012-07-25 16:28:13 【问题描述】:

在我的一个类的构造函数中,我将 Windows 函数 CreateThread 作为最后一个操作。创建线程以立即执行,我将类的 this 指针作为lpParameter 传递。

在线程过程中,我将传递回的参数转换为我的类的指针并将其命名为pThis

我可以看到pThis 指向与我调用CreateThread 时传递的this 指针相同的内存位置。但是,如果我查看pThis-&gt;... 访问的成员变量,它们都有错误的值。

我希望this指针所属的类中使用的this-&gt;member_variable的值与我在线程过程中写入pThis-&gt;member_variable时得到的值相同。

如果我在另一个成员函数(不是构造函数)中调用CreateThread,一切都会正常运行。

因此问题是:是否禁止从 C++ 类的构造函数中调用 Windows 函数CreateThread?如果有,有什么问题?

澄清:

1) 我可以确认该对象始终存在。只有当整个程序结束时,对象才会超出范围。正如我已经说过的:从其他成员函数调用CreateThread 确实有效。

2) 更正了“有线”错字,应该是“奇怪”,抱歉。

一些代码:

我尝试发布代码 sn-ps 将事情减少到最低限度,同时保持“故障”部分。

class CTimerW32 : public CTimer

    public:
        CTimerW32();
        ~CTimerW32();

    private:
        static void CALLBACK TimerCallback(LPVOID lpParam, BOOLEAN bReason);
        static DWORD WINAPI WaitCompletition(LPVOID lpParam);

    private:
        HANDLE m_hCompletitionEvent;
        HANDLE m_hCompletitionThread;
        bool m_bStartDeferred;
;

您可以放心地忽略基类CTimer,因为它只是一个抽象基类,可以在不同平台上构建。

CTimerW32::CTimerW32()

    m_bStartDeferred= false;
    m_hCompletitionEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
    m_hCompletitionThread= CreateThread(NULL, 0, WaitCompletition, this, 0, NULL);

在这里我可以看到m_hCompletitionEvent 在调用CreateEvent 之后是有效的。

DWORD WINAPI CTimerW32::WaitCompletition(LPVOID lpParam)

    CTimerW32* pThis;
    DWORD dwRet;

    pThis= (CTimerW32*)(lpParam);

    while (true) 
        // just wait for the completition event to be signaled
        dwRet= WaitForSingleObject(pThis->m_hCompletitionEvent, INFINITE);

        // ...
        if (pThis->m_bStartDeferred) 
            // ...
        
    

调用WaitForSingleObject 时出现问题。如前所述,CTimerW32(现在为pThis)类的对象的 this 指针在线程创建期间仍然具有与 this 指针相同的值。然而pThis-&gt;m_hCompletitionEvent 中的句柄似乎是随机数据。这不是在构造函数中调用CreateEvent 后观察到的值。

【问题讨论】:

线程运行时对象是否仍然存在?到时候不是在原线程中被破坏了吗? 线程工作时,你确定对象一直存在吗? 您能否发布一些代码:pThis 的声明、您对CreateThread 的调用以及您在哪里将pThis 转换为您的班级类型? “奇怪”是什么意思?你期待什么价值观,你看到了什么? 【参考方案1】:

在构造函数中创建线程应该不是问题。此外,在运行构造函数中的任何代码以创建线程之前,您的对象应该由初始化列表完全初始化,因此初始化可能不是问题。

您正在观察的对象很可能超出范围,并且在您在新线程中观察它之前调用了它的析构函数。尝试使用 new 动态创建对象,看看是否仍然会发生这种情况,我敢打赌它不会,因为对象在超出范围时不会被销毁。

显然,您应该将指向该对象的指针保留在更高的范围内,以便最终也可以将其删除:)

【讨论】:

【参考方案2】:

在Application Verifier 的帮助下调试这个问题你可能会很幸运。如果您为您的程序打开“基本”选项,它将启用 PageHeap,当内存被释放时会立即出错。如果您正在堆栈分配计时器变量,那么您的运气就不太好,但是如果在您注意到损坏时,应该可以在调试器中看到,创建计时器的线程仍在函数中声明了 CTimerW32 函数。

最后,对于这个用例,Threadpool Timer APIs 可能比创建自己的专用线程更容易工作,并且资源消耗更少。

【讨论】:

以上是关于C++ CreateThread函数如何传递this指针作为参数的主要内容,如果未能解决你的问题,请参考以下文章

在类构造函数中将此指针传递给 CreateThread 在线程过程中表现得很奇怪

创建线程函数CreateThread的lpParameter参数怎么设置才能将在主线程中初始化的值传递给线程函数

关于_beginthreadex和CreateThread的区别

CreateThread传递多个参数的方法(利用结构体的参数指针)

c# 用Windows API CreateThread函数如何创建的线程

CreateThread线程传递结构体参数