c ++ CreateThread非静态成员没有特定成员名称
c++ CreateThread non static member without particular member name
我正在尝试创建一个具有非静态 class 成员的线程,如下所示:
template <class clName>
DWORD WINAPI StartThread(PVOID ptr) {
((clName*)(ptr))->testf(); // this is static member name I want to be able use different names with the same function
return 1;
}
class Thread {
private :
HANDLE native_handle = 0;
DWORD id = 0;
public :
template <class T,class U>
Thread(T U::*member,U* original); // I want to use different members with the same function
bool run();
}
template<class T,class U>
Thread::Thread(T U::*member, U* original)
{
native_handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)StartThread<U>,original, CREATE_SUSPENDED, &id);
}
bool Thread::run() {
DWORD res = ResumeThread(native_handle);
if (res == (DWORD)-1) return false;
return true;
}
class testt {
public :
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread t(&testt::testf,this);
t.run();
}
};
int main() {
testt tt;
tt.doIt();
}
如您所见,我只能 运行 特定成员,因此此方法不可移植,不能用于任何 class 或成员。
我知道我可以轻松使用 std::thread
,但我正在做一个我不应该使用任何 C++ 运行 时间的项目,所以我正在为 [=12 创建包装器=]/delete
、线程、文件 I/O 等。否则,我总是使用 std::thread
,这太棒了。在这个项目中,我只能使用 Win32 API。
模板参数可以是 pointer to member,因此您可以这样扩充 StartThread
,并使 Thread::Thread
的指向成员的指针参数成为模板参数。您不能向构造函数模板提供显式模板参数,因此您必须使用特殊的“标签”参数来传达它们:
template<class C,class T,T C::*P>
DWORD WINAPI StartThread(PVOID ptr) {
(static_cast<C*>(ptr)->*P)();
return 1;
}
template<class C,class T,T C::*P>
struct Tag {};
class Thread {
private :
HANDLE native_handle = 0;
DWORD id = 0;
public :
template<class C,class T,T C::*P>
Thread(Tag<C,T,P>,C*);
bool run();
};
template<class C,class T,T C::*P>
Thread::Thread(Tag<C,T,P>,C* original)
{
native_handle = CreateThread(0, 0, StartThread<C,T,P>,original,
CREATE_SUSPENDED, &id);
}
bool Thread::run() {
DWORD res = ResumeThread(native_handle);
if (res == (DWORD)-1) return false;
return true;
}
class testt {
public :
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread t(Tag<testt,void(),&testt::testf>(),this);
t.run();
}
};
int main() {
testt tt;
tt.doIt();
}
注意void()
函数类型作为成员类型T
; C++17 提供了更简单的语法,在模板参数的类型中使用 auto
。
或者通过创建一个包含 T*
和 T::*
的结构并将指向它的指针作为您的 PVOID
传递来将其保留为普通参数。这种方式的技巧是您需要使用类型擦除来正确销毁该块,或者使用 reinterpret_cast
将指针临时存储在固定类型下(就像 StartThread
已经完成的那样)。
如果不使用 C++ 运行时,如 std::thread
和 std::function
,您的选择会有点受限。
试试像这样的东西:
template <class U>
class Thread {
private:
HANDLE native_handle = 0;
DWORD id = 0;
U *object;
void (U::*object_member)();
static DWORD WINAPI ThreadProc(PVOID ptr);
public:
Thread(void U::*member, U* obj);
bool start();
};
template<class U>
DWORD WINAPI Thread<U>::ThreadProc(PVOID ptr) {
Thread *t = static_cast<Thread*>(ptr);
U *obj = t->object;
void (U::*member)() = t->object_member;
(obj->*member)();
return 1;
}
template<class U>
Thread<U>::Thread(void U::*member, U* obj) :
object_member(member), object(obj) {
native_handle = CreateThread(0, 0, &ThreadProc, this, CREATE_SUSPENDED, &id);
}
template <class U>
bool Thread<U>::start() {
return (ResumeThread(native_handle) != (DWORD)-1);
}
class testt {
public:
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread<testt> t(&testt::testf, this);
t.start();
}
};
int main() {
testt tt;
tt.doIt();
}
否则,您可能不得不求助于类似这样的方法:
class Thread {
private:
HANDLE native_handle = 0;
DWORD id = 0;
void (*func)(void*);
void *param;
static DWORD WINAPI ThreadProc(PVOID ptr);
public:
Thread(void (*f)(void*), void* p);
bool start();
};
DWORD WINAPI Thread::ThreadProc(PVOID ptr) {
Thread *t = static_cast<Thread*>(ptr);
void (*func)(void*) = t->func;
(*func)(t->param);
return 1;
}
Thread::Thread(void (*f)(void*), void *p) :
func(f), param(p) {
native_handle = CreateThread(0, 0, &ThreadProc, this, CREATE_SUSPENDED, &id);
}
bool Thread::start() {
return (ResumeThread(native_handle) != (DWORD)-1);
}
class testt {
private:
static void proc(void *p) {
static_cast<testt*>(p)->testf();
}
public:
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread t(&testt::proc, this);
t.start();
}
};
int main() {
testt tt;
tt.doIt();
}
要由 CreateThread
执行的应用程序定义函数必须具有签名:
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
如果我们使用 class 成员(非静态)函数 - 它必须有签名
class testt {
ULONG WINAPI testf();
};
需要记住每个非静态成员函数都得到指向 this 的指针作为第一个参数。只是我们没有明确声明它。结果 ULONG WINAPI testf(/*testt* this*/);
与 ThreadProc callback 函数完全匹配。我们可以将它用作线程入口点。
In this project, I have to use Win32 API only.
我不认为这个线程具体需要使用包装器 api,但代码可能如下所示:
template <class U>
class Thread
{
HANDLE _hThread;
DWORD _id;
public :
Thread() : _hThread(0) {}
~Thread()
{
if (_hThread) CloseHandle(_hThread);
}
ULONG Create(ULONG (WINAPI U::*member)(), U* This)
{
union {
LPTHREAD_START_ROUTINE lpStartAddress;
ULONG (WINAPI U::*_member)();
};
_member = member;
if (_hThread = CreateThread(0, 0, lpStartAddress, This, CREATE_SUSPENDED, &_id))
{
return NOERROR;
}
return GetLastError();
}
ULONG run()
{
return ResumeThread(_hThread) == MAXULONG ? GetLastError() : NOERROR;
}
ULONG wait()
{
return WaitForSingleObject(_hThread, INFINITE);
}
};
class testt {
PCWSTR _txt, _caption;
public :
testt(PCWSTR txt, PCWSTR caption) : _txt(txt), _caption(caption) { }
ULONG WINAPI testf() {
return MessageBox(0, _txt, _caption, 0);
}
void doIt() {
Thread<testt> t;
if (t.Create(&testt::testf, this) == NOERROR)
{
if (t.run() == NOERROR)
{
t.wait();
}
}
}
};
void demo()
{
testt o(L"text", L"caption");
o.doIt();
}
但是对于没有模板的比较代码class,而是直接启动线程到class成员函数:
class testt {
PCWSTR _txt, _caption;
public :
testt(PCWSTR txt, PCWSTR caption) : _txt(txt), _caption(caption) { }
ULONG WINAPI testf() {
return MessageBox(0, _txt, _caption, 0);
}
void doIt() {
union {
LPTHREAD_START_ROUTINE lpStartAddress;
ULONG (WINAPI testt::*pfn)();
};
pfn = &testt::testf;
if (HANDLE hThread = CreateThread(0, 0, lpStartAddress, this, 0, 0))
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
}
};
void demo()
{
testt o(L"text", L"caption");
o.doIt();
}
我以 std::thread 的 winapi 替代品结束,效果相同,可能更好
class letTest {
private :
void pri(int u,float g, char l) {
MessageBoxA(0, 0, 0, 0);
}
public :
int doIt(int o) {
auto t = thread(&letTest::pri, this,5,4.2,'k'); // works well with any number and type of parameters
t.join();
return 5;
}
};
也有常用的功能
void ltest(int i) {
MessageBoxA(0, to_string(i).c_str(), 0, 0);
}
int main() {
auto t = thread(ltest, 4);
t.join();
}
我正在尝试创建一个具有非静态 class 成员的线程,如下所示:
template <class clName>
DWORD WINAPI StartThread(PVOID ptr) {
((clName*)(ptr))->testf(); // this is static member name I want to be able use different names with the same function
return 1;
}
class Thread {
private :
HANDLE native_handle = 0;
DWORD id = 0;
public :
template <class T,class U>
Thread(T U::*member,U* original); // I want to use different members with the same function
bool run();
}
template<class T,class U>
Thread::Thread(T U::*member, U* original)
{
native_handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)StartThread<U>,original, CREATE_SUSPENDED, &id);
}
bool Thread::run() {
DWORD res = ResumeThread(native_handle);
if (res == (DWORD)-1) return false;
return true;
}
class testt {
public :
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread t(&testt::testf,this);
t.run();
}
};
int main() {
testt tt;
tt.doIt();
}
如您所见,我只能 运行 特定成员,因此此方法不可移植,不能用于任何 class 或成员。
我知道我可以轻松使用 std::thread
,但我正在做一个我不应该使用任何 C++ 运行 时间的项目,所以我正在为 [=12 创建包装器=]/delete
、线程、文件 I/O 等。否则,我总是使用 std::thread
,这太棒了。在这个项目中,我只能使用 Win32 API。
模板参数可以是 pointer to member,因此您可以这样扩充 StartThread
,并使 Thread::Thread
的指向成员的指针参数成为模板参数。您不能向构造函数模板提供显式模板参数,因此您必须使用特殊的“标签”参数来传达它们:
template<class C,class T,T C::*P>
DWORD WINAPI StartThread(PVOID ptr) {
(static_cast<C*>(ptr)->*P)();
return 1;
}
template<class C,class T,T C::*P>
struct Tag {};
class Thread {
private :
HANDLE native_handle = 0;
DWORD id = 0;
public :
template<class C,class T,T C::*P>
Thread(Tag<C,T,P>,C*);
bool run();
};
template<class C,class T,T C::*P>
Thread::Thread(Tag<C,T,P>,C* original)
{
native_handle = CreateThread(0, 0, StartThread<C,T,P>,original,
CREATE_SUSPENDED, &id);
}
bool Thread::run() {
DWORD res = ResumeThread(native_handle);
if (res == (DWORD)-1) return false;
return true;
}
class testt {
public :
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread t(Tag<testt,void(),&testt::testf>(),this);
t.run();
}
};
int main() {
testt tt;
tt.doIt();
}
注意void()
函数类型作为成员类型T
; C++17 提供了更简单的语法,在模板参数的类型中使用 auto
。
或者通过创建一个包含 T*
和 T::*
的结构并将指向它的指针作为您的 PVOID
传递来将其保留为普通参数。这种方式的技巧是您需要使用类型擦除来正确销毁该块,或者使用 reinterpret_cast
将指针临时存储在固定类型下(就像 StartThread
已经完成的那样)。
如果不使用 C++ 运行时,如 std::thread
和 std::function
,您的选择会有点受限。
试试像这样的东西:
template <class U>
class Thread {
private:
HANDLE native_handle = 0;
DWORD id = 0;
U *object;
void (U::*object_member)();
static DWORD WINAPI ThreadProc(PVOID ptr);
public:
Thread(void U::*member, U* obj);
bool start();
};
template<class U>
DWORD WINAPI Thread<U>::ThreadProc(PVOID ptr) {
Thread *t = static_cast<Thread*>(ptr);
U *obj = t->object;
void (U::*member)() = t->object_member;
(obj->*member)();
return 1;
}
template<class U>
Thread<U>::Thread(void U::*member, U* obj) :
object_member(member), object(obj) {
native_handle = CreateThread(0, 0, &ThreadProc, this, CREATE_SUSPENDED, &id);
}
template <class U>
bool Thread<U>::start() {
return (ResumeThread(native_handle) != (DWORD)-1);
}
class testt {
public:
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread<testt> t(&testt::testf, this);
t.start();
}
};
int main() {
testt tt;
tt.doIt();
}
否则,您可能不得不求助于类似这样的方法:
class Thread {
private:
HANDLE native_handle = 0;
DWORD id = 0;
void (*func)(void*);
void *param;
static DWORD WINAPI ThreadProc(PVOID ptr);
public:
Thread(void (*f)(void*), void* p);
bool start();
};
DWORD WINAPI Thread::ThreadProc(PVOID ptr) {
Thread *t = static_cast<Thread*>(ptr);
void (*func)(void*) = t->func;
(*func)(t->param);
return 1;
}
Thread::Thread(void (*f)(void*), void *p) :
func(f), param(p) {
native_handle = CreateThread(0, 0, &ThreadProc, this, CREATE_SUSPENDED, &id);
}
bool Thread::start() {
return (ResumeThread(native_handle) != (DWORD)-1);
}
class testt {
private:
static void proc(void *p) {
static_cast<testt*>(p)->testf();
}
public:
void testf() {
MessageBoxA(0, "working", "", 0);
}
void doIt() {
Thread t(&testt::proc, this);
t.start();
}
};
int main() {
testt tt;
tt.doIt();
}
要由 CreateThread
执行的应用程序定义函数必须具有签名:
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
如果我们使用 class 成员(非静态)函数 - 它必须有签名
class testt {
ULONG WINAPI testf();
};
需要记住每个非静态成员函数都得到指向 this 的指针作为第一个参数。只是我们没有明确声明它。结果 ULONG WINAPI testf(/*testt* this*/);
与 ThreadProc callback 函数完全匹配。我们可以将它用作线程入口点。
In this project, I have to use Win32 API only.
我不认为这个线程具体需要使用包装器 api,但代码可能如下所示:
template <class U>
class Thread
{
HANDLE _hThread;
DWORD _id;
public :
Thread() : _hThread(0) {}
~Thread()
{
if (_hThread) CloseHandle(_hThread);
}
ULONG Create(ULONG (WINAPI U::*member)(), U* This)
{
union {
LPTHREAD_START_ROUTINE lpStartAddress;
ULONG (WINAPI U::*_member)();
};
_member = member;
if (_hThread = CreateThread(0, 0, lpStartAddress, This, CREATE_SUSPENDED, &_id))
{
return NOERROR;
}
return GetLastError();
}
ULONG run()
{
return ResumeThread(_hThread) == MAXULONG ? GetLastError() : NOERROR;
}
ULONG wait()
{
return WaitForSingleObject(_hThread, INFINITE);
}
};
class testt {
PCWSTR _txt, _caption;
public :
testt(PCWSTR txt, PCWSTR caption) : _txt(txt), _caption(caption) { }
ULONG WINAPI testf() {
return MessageBox(0, _txt, _caption, 0);
}
void doIt() {
Thread<testt> t;
if (t.Create(&testt::testf, this) == NOERROR)
{
if (t.run() == NOERROR)
{
t.wait();
}
}
}
};
void demo()
{
testt o(L"text", L"caption");
o.doIt();
}
但是对于没有模板的比较代码class,而是直接启动线程到class成员函数:
class testt {
PCWSTR _txt, _caption;
public :
testt(PCWSTR txt, PCWSTR caption) : _txt(txt), _caption(caption) { }
ULONG WINAPI testf() {
return MessageBox(0, _txt, _caption, 0);
}
void doIt() {
union {
LPTHREAD_START_ROUTINE lpStartAddress;
ULONG (WINAPI testt::*pfn)();
};
pfn = &testt::testf;
if (HANDLE hThread = CreateThread(0, 0, lpStartAddress, this, 0, 0))
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
}
};
void demo()
{
testt o(L"text", L"caption");
o.doIt();
}
我以 std::thread 的 winapi 替代品结束,效果相同,可能更好
class letTest {
private :
void pri(int u,float g, char l) {
MessageBoxA(0, 0, 0, 0);
}
public :
int doIt(int o) {
auto t = thread(&letTest::pri, this,5,4.2,'k'); // works well with any number and type of parameters
t.join();
return 5;
}
};
也有常用的功能
void ltest(int i) {
MessageBoxA(0, to_string(i).c_str(), 0, 0);
}
int main() {
auto t = thread(ltest, 4);
t.join();
}