c++ A problem when create a thread in a class

Started by
9 comments, last by wanmaple 10 years, 7 months ago

Dear everyone, I am writing a singleton class to manage a thread, here's the code:


#include <windows.h>

typedef class MsgListener
{
private:
    HANDLE _threadHandle;
    DWORD _threadId;
    static MsgListener *_instance;
    MsgListener();
    DWORD WINAPI Listen(LPVOID param);
public:
    static MsgListener *GetInstance();
    void StartListen();
    void StopListen();
} MSGLISTENER, *LPMSGLISTENER;

MsgListener *MsgListener::_instance = new MsgListener();
MsgListener::MsgListener() 
{ 
    _threadHandle = 0;
    _threadId = 0;
}
DWORD WINAPI MsgListener::Listen(LPVOID param) 
{ 
    // The method to run in a new thread....
}
MsgListener *MsgListener::GetInstance()
{
    if (!_instance)
        _instance = new MsgListener();
    return _instance;
}
void MsgListener::StartListen()
{
    // Here, the compiler give the error:
    // cannot convert 'MsgListener::Listen' from type 'DWORD (MsgListener::)(LPVOID) { aka long unsigned int (MsgListener::)(void*) }' to type 'LPTHREAD_START_ROUTINE { aka long unsigned int (__attribute__((__stdcall__)) *)(void*) }'
    this->_threadHandle = CreateThread(NULL, 0, Listen, 0, &_threadId);
}
void MsgListener::StopListen()
{
    CloseHandle(_threadHandle);
}

The ide I use is Code::Blocks and the compiler is GNU GCC COMPILER.

How to convert the function pointer in a class to the normal function pointer in C? And I really don't know the difference between these two kind of function pointers. Where does each kind of function pointer save in the memory?

Do my best to improve myself, to learn more and more...

Advertisement
Just about everything you wrote in the post fits in the "probably doing it wrong" category. Singletons should generally be avoided. Threading is not a beginner's topic and is a frequent source of nightmares to engine developers, unguarded shared access is another source of nightmares. Member function pointers require a good understanding of how pointers and classes work in c++. Tagging everything as 'WINAPI' calling convention. And all of that while thinking about conserving memory.

Every one of those has an occasional use, but usually as exceptions that don't fit the usual rules of good design.

What is the actual problem you are trying to solve? What are you trying to build? Just based on the names it looks like something to do with passing messages. There are many excellent existing solutions for that which are much less complex than what you are asking.

Just about everything you wrote in the post fits in the "probably doing it wrong" category. Singletons should generally be avoided. Threading is not a beginner's topic and is a frequent source of nightmares to engine developers, unguarded shared access is another source of nightmares. Member function pointers require a good understanding of how pointers and classes work in c++. Tagging everything as 'WINAPI' calling convention. And all of that while thinking about conserving memory.

Every one of those has an occasional use, but usually as exceptions that don't fit the usual rules of good design.

What is the actual problem you are trying to solve? What are you trying to build? Just based on the names it looks like something to do with passing messages. There are many excellent existing solutions for that which are much less complex than what you are asking.

Thanks very much. Could you recommand some articles or books about c++ lower mechanisms and theory of c++ class. I always feel confused about some concepts in c++ class.

Do my best to improve myself, to learn more and more...

How to convert the function pointer in a class to the normal function pointer in C?

You cannot directly specify an instance method as method / callback parameter in Windows API in general, and not in CreateThread in particular. This is because internally instance methods have an additional parameter pointing to the class instance, so the method signature does not match the signature required by CreateThread.
The usual workaround is to have a static method, pass a pointer to the instance as lpParameter, and dispatch the call in the static method to an instance method, using that parameter.


class MsgListener
{
private:
    HANDLE _threadHandle;
    DWORD _threadId;
    static MsgListener *_instance;
    MsgListener();
    DWORD Listen();
    static DWORD WINAPI StaticListen(LPVOID param);
public:
    static MsgListener *GetInstance();
    void StartListen();
    void StopListen();
};

MsgListener *MsgListener::_instance = new MsgListener();
MsgListener::MsgListener() 
{ 
    _threadHandle = 0;
    _threadId = 0;
}
DWORD WINAPI MsgListener::StaticListen(LPVOID param) 
{
	MsgListener* listener = reinterpret_cast<MsgListener*>(param);
	return listener->Listen();
}
DWORD MsgListener::Listen() 
{ 
    // The method to run in a new thread....
	return 0;
}
MsgListener *MsgListener::GetInstance()
{
    if (!_instance)
        _instance = new MsgListener();
    return _instance;
}
void MsgListener::StartListen()
{
    this->_threadHandle = CreateThread(NULL, 0, &MsgListener::StaticListen, this, 0, &_threadId);
}
void MsgListener::StopListen()
{
    CloseHandle(_threadHandle);
}

However, I'd use the threading support in C++11 instead. It is so much easier to specify an arbitrary worker method, even an instance method, using the std::thread ctor:

http://en.cppreference.com/w/cpp/thread/thread/thread

Thanks very much. Could you recommand some articles or books about c++ lower mechanisms and theory of c++ class. I always feel confused about some concepts in c++ class.

Accelerated C++ by Koenig and Moo, and C++ Primer by Lippmann, LaJoie and Moo, are both frequently recommended for beginners in C++.

Even so, what problem are you trying to solve? People can probably point you to excellent resources for whatever specific problem you are looking to solve that are less complex than the path you were traveling.

Could you recommand some articles or books about c++ lower mechanisms and theory of c++ class. I always feel confused about some concepts in c++ class.

http://www.parashift.com/c++-faq/

http://www.parashift.com/c++-faq/memfnptr-vs-fnptr.html

Thanks very much. Could you recommand some articles or books about c++ lower mechanisms and theory of c++ class. I always feel confused about some concepts in c++ class.

Accelerated C++ by Koenig and Moo, and C++ Primer by Lippmann, LaJoie and Moo, are both frequently recommended for beginners in C++.

Even so, what problem are you trying to solve? People can probably point you to excellent resources for whatever specific problem you are looking to solve that are less complex than the path you were traveling.

Thanks, I want to create a new thread to watch the keyboard state and mouse state in DirectInput, I want to use a infinite loop to watch the message by using the GetDevice function in DirectInput. So I want to define a class which is to manage the listen thread.

Do my best to improve myself, to learn more and more...

Could you recommand some articles or books about c++ lower mechanisms and theory of c++ class. I always feel confused about some concepts in c++ class.

http://www.parashift.com/c++-faq/

http://www.parashift.com/c++-faq/memfnptr-vs-fnptr.html

Thanks, bro~

How to convert the function pointer in a class to the normal function pointer in C?

You cannot directly specify an instance method as method / callback parameter in Windows API in general, and not in CreateThread in particular. This is because internally instance methods have an additional parameter pointing to the class instance, so the method signature does not match the signature required by CreateThread.
The usual workaround is to have a static method, pass a pointer to the instance as lpParameter, and dispatch the call in the static method to an instance method, using that parameter.


class MsgListener
{
private:
    HANDLE _threadHandle;
    DWORD _threadId;
    static MsgListener *_instance;
    MsgListener();
    DWORD Listen();
    static DWORD WINAPI StaticListen(LPVOID param);
public:
    static MsgListener *GetInstance();
    void StartListen();
    void StopListen();
};

MsgListener *MsgListener::_instance = new MsgListener();
MsgListener::MsgListener() 
{ 
    _threadHandle = 0;
    _threadId = 0;
}
DWORD WINAPI MsgListener::StaticListen(LPVOID param) 
{
	MsgListener* listener = reinterpret_cast<MsgListener*>(param);
	return listener->Listen();
}
DWORD MsgListener::Listen() 
{ 
    // The method to run in a new thread....
	return 0;
}
MsgListener *MsgListener::GetInstance()
{
    if (!_instance)
        _instance = new MsgListener();
    return _instance;
}
void MsgListener::StartListen()
{
    this->_threadHandle = CreateThread(NULL, 0, &MsgListener::StaticListen, this, 0, &_threadId);
}
void MsgListener::StopListen()
{
    CloseHandle(_threadHandle);
}

However, I'd use the threading support in C++11 instead. It is so much easier to specify an arbitrary worker method, even an instance method, using the std::thread ctor:

http://en.cppreference.com/w/cpp/thread/thread/thread

Yeah, you are right. When I use a static method, the Singleton is meaningless, so I think I ought to change a design way to watch the device state. Thanks very much, bro.

Do my best to improve myself, to learn more and more...


I want to create a new thread to watch the keyboard state and mouse state in DirectInput

Don't:

http://msdn.microsoft.com/en-us/library/windows/desktop/ee416842%28v=vs.85%29.aspx

"The use of DirectInput for keyboard and mouse input is not recommended. You should use Windows messages instead."


When I use a static method, the Singleton is meaningless

You should avoid singletons, but not for this reason. The static thread method is just used to dispatch the call to the instance-specific handler. The "real" handler is not static.

This topic is closed to new replies.

Advertisement