[C++]Pass member function to _beginthread()

Started by
10 comments, last by directNoob 17 years, 10 months ago
Hello. I have a problem with a function. First of all the function:
void __cdecl CallWritingThread(void *);
This function is a member of my class
class CLogSystem
The problem is, when I want to write for example an error to a file, I want to do this by a seperate thread. So I want to start the new thread with the function which writes this message into this file. So I start the thread by
_beginthread(*startAdress, stackSize, Param)
The parameter must be a pointer to the thread proc with this notation:
void (*thread)(void *)
As you can see, the function which I posted first, has this structure. When I write:
_beginthread(CallWritingThread, 0, NULL);
The compiler says:
'CLogSystem::CallWritingThread': function call missing argument list; use '&CLogSystem::CallWritingThread' to create a pointer to member
So I listened to it and wrote this:
_beginthread(&CLogSystem::CallWritingThread, 0, NULL);
But the compiler picked at this code again with that:
'_beginthread' : cannot convert parameter 1 from 'void (__cdecl CLogSystem::* )(void *)' to 'void (__cdecl *)(void *)'
I absolutly don´t know what the compiler want!? Please help Alex
Advertisement
Pointers to non-static member functions (void (Foo::*)()) are not compatible with 'regular' function pointers (void (*)()). Therefore, you cannot pass them to a C API, like the Win32 API.

What you need to do is write a normal (non-member or static member) function taking a void* parameter (_beginthread() allows that), and in that function cast the parameter back to the proper object pointer type and use it to call whichever member function it is you wanted to call in the first place. Then in _beginthread, you pass the pointer as void* user data:

class Foo{public:   void doit() { /* ... */ }   static void call_doit(void* ptr)   {      reinterpret_cast<Foo*>(ptr)->doit();   }};int main(){   Foo f;   _beginthread(&Foo::doit_, 0, &f);}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Thanks for that fast response!

Is there any other solution? I mean the cast.

The class
 CLogSystem : public CSingleton

is derived from a singleton class.

And I can say, that I have declared one in the main file.

So can I use this singleton object of the class CLogSystem for this?

The problem is that I want to hold the functionality togehter.

Alex
Quote:Original post by directNoob
Is there any other solution? I mean the cast.


No. _beginthread work with a void*, you will need the cast.

Quote:So can I use this singleton object of the class CLogSystem for this?


If you have a singleton, then of course, you don't need to pass the object pointer to _beginthread, you can just retrieve it in the function itself. But then again, if you have a fscking singleton, why do you need a member function? It doesn't buy you anything except complications.

Quote:The problem is that I want to hold the functionality togehter.


Keeping things together in the same file is often sufficient. It doesn't all have to be in a single class. Namespaces can help, too.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
If you're using a singleton (fscking is right Fruny lol) why not make the function static... You're entire class basically is.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Hi.

Now everything is working just fine. But first I wanted to use a html file for capturing the msgs. But nothing worked, it worked but not well. Now I use a .txt file and the next problem occures.

The problem is that the escape sequences \n and \r don´t work, but \t for example works.

I use the way with the handles. this means, I use
CreateFile()
and
WriteFile()


Furthermore, I use wide characters.

What can I do now?

Alex

[Edited by - directNoob on June 18, 2006 7:31:05 AM]
What if it were not a static class, and the passed function should know about its parent. I mean that the function taking a function pointer should be general to take both normal function and member together.

SORRY FOR HIJACKING THE THREAD :)
[ my blog ]
This should show you a simple way to make a thread call a member function using a static function and sending the instance as a parameter to the _beginthread function. This is some ugly code I just hacked together (haven't been using C++ for a while) which should not be used directly as it is, but you get the general idea. The Sleep calls are there to make sure the printing doesn't collide - so as I said uglyuglyugly ;)

#include <windows.h>#include <iostream>#include <process.h>class TestBase{	protected:		std::ostream* m_pos;	public:		TestBase(std::ostream* pos) { m_pos = pos; }		virtual ~TestBase() { }		virtual void Print() = 0;				static void Caller(void* param)		{			TestBase* tb = (TestBase*)param;			tb->Print();						delete tb;		}};class TestClass : public TestBase{	public:		TestClass(std::ostream* pos) : TestBase(pos) { }		void Print() { (*m_pos) << "Test" << std::endl; }};class TestClassX : public TestBase{	public:		TestClassX(std::ostream* pos) : TestBase(pos) { }		void Print() { (*m_pos) << "TestXXX" << std::endl; }};int main(){	TestBase* a = new TestClass(&std::cout);	TestBase* b = new TestClassX(&std::cout);	_beginthread(TestBase::Caller, 0, (void*)a);	Sleep(1000);	_beginthread(TestBase::Caller, 0, (void*)b);	Sleep(1000);	return 0;}


arithma:
You could make a new function that takes a functor as a parameter instead of a function pointer. This implementation of the functor is a modified version of the one in the enginuity series. I've added a void* parameter to pass them the parameters from the beginthread function. (This code is also a quick hack, but I guess you get the point):

Modified functor
class Functor{   public:      virtual void operator ()(void* args) const =0;      virtual ~Functor() { }};template<class T>class ClassFunctor : public Functor{   protected:      typedef void (T::*FuncType)(void* args);      T* m_obj;      FuncType m_func;   public:      ClassFunctor(T *o, FuncType f)          : m_obj(o), m_func(f)      {		      }         void operator ()(void* args) const      {         (m_obj->*m_func)(args);      }};class FunctionFunctor : public Functor{   protected:      typedef void (*FuncType)(void* args);      FuncType m_func;   public:      FunctionFunctor(FuncType f)          : m_func(f)      {		      }         void operator ()(void* args) const      {         (*m_func)(args);      }};


BeginThread
struct FunctDataPair{   const Functor* pFunctor;   void* argList;};void FunctorCaller(void *arglist){   FunctDataPair* data = (FunctDataPair*)(arglist);   (*data->pFunctor)(data->argList);   delete data;}void BeginThread(const Functor* ftor, unsigned int stackSize, void *argList){   FunctDataPair* data = new FunctDataPair();   data->pFunctor = ftor;   data->argList = argList;	   _beginthread(FunctorCaller, stackSize, (void*)data);}


Test
class TestClass{   private:      std::string m_text;   public:      TestClass(const std::string& text)         : m_text(text)      {      }      void Print(void* args)      {         std::cout << m_text.c_str() << " - " << (int)args << std::endl;      }};void SomeFunction(void* args){   std::cout << "::SomeFunction - " << (int)args << std::endl;}int main(){   TestClass tc("TestClass::Print");	   ClassFunctor<TestClass> cf(&tc, &TestClass::Print);   FunctionFunctor ff(SomeFunction);   BeginThread(&cf, 0, (void*)1234);   Sleep(1000);   BeginThread(&ff, 0, (void*)7654);   Sleep(1000);   return 0;}


[Edited by - e-u-l-o-g-y on June 18, 2006 10:38:09 AM]
my-eulogy - A blog about coding and gfxsdgi - Semi-Daily Game IdeaChunkyHacker - Viewer for Relic chunky formats (used in DOW)
Quote:Original post by arithma
What if it were not a static class, and the passed function should know about its parent. I mean that the function taking a function pointer should be general to take both normal function and member together.


It cannot. The windows API is a C API. C knows nothing about pointers to member functions. And it doesn't support function overloading, so you could not even have two different functions to make it work transparently.

You cannot use a pointer to member where a pointer is expected, nor vice-versa.

Pointers to member functions are not the same thing as regular function pointers. They do not even have the same size. They do not contain the address of the function to be called. Heck, two pointers to member might even be structured differently. Two different compilers might also implement them differently (and in fact, they often do), meaning you can't even safely pass them to a library that has been compiled with a different compiler.

You cannot use a pointer to member where a pointer is expected, nor vice-versa.

For more discussion of the guts of a pointer-to-member, see this article. If the article goes over your head, then just remember this:

You cannot use a pointer to member where a pointer is expected, nor vice-versa.

[Edited by - Fruny on June 18, 2006 11:14:27 AM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Fruny
You cannot use a pointer to member where a pointer is expected, nor vice-versa.


Are you trying to say something? [grin]

All this mucking about is why I use boost::thread for my MT needs [smile]

This topic is closed to new replies.

Advertisement