Sign in to follow this  

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

This topic is 4195 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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);
}

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
Quote:
Original post by phantom
All this mucking about is why I use boost::thread for my MT needs [smile]

Ditto. Type safety, able to handle member functions, non member functions, and funciton objects, cross platform... the list of reasons it beats the boxers off _beginthread & co. goes on.

Share this post


Link to post
Share on other sites
Ok, when I quickly come back to the original topic before you continue your discussion.

How can I test if a thread runs simultaneously?

The problem is, when I print out the msgs, I want to caputure in the file, by
MessageBox()
, the program starts this first when some partucular code sections are passed but it should printed it out(on the screen for testing) before that particular sections.

The Thread works, but I don´t know if it works simultaneously...

The problem is: The progam fills a msg stack(which is on the stack) in the main program and the thread should print these msgs in the file while the main program continues it´s action. I´m confused because, when I look at that msg stack in the debugger, it is full. And when I set a breakpoint in the thread function, I can see that it just starts to clean this msg stack but it should has begun while the main program is filling this msg stack up, you understand? I hope so!!!
The idea is when an error-string or msg occures in the main program, it calls a function and this function sends this msg on the msg stack. When this is the first msg, a thread gets started. Maybe, while the thread is working, another msg or error might occur and the function called in the main program stores this other msg or error in the msg stack. When the thread isn´t finished till this moment, the new msg or error-string goes on the next slot in that msg stack. And so on. And when the thread has written it current sting in the file, it cleans the allocated storage on the msg stack, so it knows when it is on that position again, that there is no more msg. And when the main msg stack is full, there is a temp msg stack which will handle the forthcomming msgs.

When no msg is left, in both msg stacks, the thread gets closed.
It is just the logic behind my idea, i hope it is enough to understand my problem!?

Greetings
Alex

Share this post


Link to post
Share on other sites

This topic is 4195 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this