C++创建非特定成员的非静态成员线程
我试图创建一个具有非静态类成员的线程,如下所示:C++创建非特定成员的非静态成员线程,c++,templates,winapi,non-static,createthread,C++,Templates,Winapi,Non Static,Createthread,我试图创建一个具有非静态类成员的线程,如下所示: 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 {
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();
}
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();
}
如您所见,我只能运行特定的成员,因此此方法不可移植,并且不能用于任何类或成员
我知道我可以很容易地使用STD::线程,但是我在做一个我不应该使用任何C++运行时的项目,所以我正在为新的/删除、线程、文件I/O等创建包装器。否则,我总是使用STD::线程,这太棒了。在这个项目中,我只需要使用Win32 API。
模板参数可以是,因此您可以通过这种方式扩展StartThread,并将Thread::Thread指向成员参数的指针设置为模板参数。您不能向构造函数模板提供显式模板参数,因此必须使用特殊的“tag”参数来传递它们: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();
}
注:空心函数类型为构件类型T;更简单的语法在C++17中可用,在模板参数的类型中使用auto
或者通过创建一个包含T*和T::*的结构并将指向它的指针作为PVOID传递,将其保留为普通参数。这样做的诀窍是,您需要使用类型擦除来正确地破坏该块,否则,使用RealTytRCAST来存储在StimeToX已经完成的固定类型下临时指针。 < P>不使用C++运行时,如STD::Trand和STD::Foad,您的选项有点限制。 尝试类似以下内容:
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();
}
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();
}
否则,您可能不得不采取以下措施:
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();
}
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();
}
要由执行的应用程序定义的函数必须具有签名:
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
如果我们使用类成员非静态函数-它必须有签名
class testt {
ULONG WINAPI testf();
};
需要记住的是,每个非静态成员函数都将指向它的指针作为第一个参数。只是我们没有明确声明它。因此,ULONG WINAPI testf/*testt*this*/;与功能完全匹配。我们可以使用它作为线程入口点
在这个项目中,我只能使用Win32 API
我不了解该线程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();
}
我以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();
}
听起来你应该想办法摆脱那些人为的限制,因此,您可以编写自然的工作代码。如果您必须在CreateThread调用中强制转换thread proc,那么您的声明不正确。@jesperJuhl我认为有一种方法可以像标准线程和boost线程那样执行this@RichardCritten为什么不正确?因为StartThread应该已经是LPTHREAD\u START\u例程。没有必要把它定义为任何不同的东西。移除强制转换,看看你的功能是否符合要求的原型。如果不行,就把它修好。使用上帝的锤子来迫使它适应是一个坏主意。我得到了这个错误:“类型转换”:无法从“重载函数”转换为“LPTHREAD\u START\u例程”@dev65因为你没有显示你的新代码,我们无法告诉你它有什么问题。将startthread更改为模板DWORD WINAPI startroutinepoid ptr{clName*ptr->*成员;返回1;}然后将构造函数更改为:native_handle=CreateThread0,0,LPTHREAD_START_例程&startrotine,original,CREATE_SUSPENDED,&id;@dev65:如果您也将member添加为构造函数的模板参数,它不应该是吗?使用此模板时,Thread::ThreadT U::*memb,U*原始无函数匹配:Thread t&testt::testf、 对于目前的情况,这是一个很棒的解决方案,请记住,我不会觉得有太多的限制,因为项目非常小,我每次都可以将我的旧代码与manual ThreadProc一起使用,但您的代码将节省很多time@RemyLabeau当我使用我得到的代码时,void是非法的,所以我使用int,然后我得到了这个错误:“Thread::ThreadTh”read&&:无法将参数1从“int\uu cdecl testt::*void”转换为“int testt::*@dev65我对代码进行了一些调整。请重试。我要到下周才能访问编译器,否则我会在发布之前检查它以完全符合标准,ThreadProc需要是外部的。C语言链接是函数类型的一部分,而此外,它需要一个自由函数,而不是静态成员。访问私有成员数据,可以安全地使用朋友。在C++中,联合技巧不起作用。通过不同类型的指针调用函数是不可定义的行为。C++没有兼容函数类型的概念。如果是同一类型,则不会。不使用无论如何是合法的联合技巧,C++不允许读一个不同的联合成员,而不是最后一个写的。并且看到它在一个特定的编译器版本中,特别是优化设置,不能证明它是合法的。未定义的行为被允许工作一些、全部或没有时间。如果它只适用于cl.exe,其他编译器会破坏违反严格别名的代码
. 这叫做优化不稳定性。我想你是对的,微软允许这样做,因为他们肯定有遗留的代码窗口,可能还有Office和其他应用程序,它们是用这个编译器构建的,并且不是严格一致的。优化不稳定代码的一个大问题是,在安装一个新的编译器版本之前,通常不会出现任何问题,然后所有的bug突然开始显现。看看他们说这段代码在什么地方没有输出