Archived

This topic is now archived and is closed to further replies.

CommanderXXL

Function Pointers as parameters?

Recommended Posts

CommanderXXL    122
Is it ppossible and if so how can i give the pointer to a function as parameter to another function? Like this: void ThreadCreate(void *Function(void)) { CreateThread(....); } Main() { ThreadCreate(&SomeFunc(parameter)); } Please help me Thanks By CommanderXXL

Share this post


Link to post
Share on other sites
Oluseyi    2116
Typedef the function pointer:
typedef void (*pVoidFunction)(void);
typedef int (*p2IntFunction)(int, int);
// declaration:
int SomeFunctionThatTakesVoidFunction(pVoidFunction pFunc)
{
pFunc();
}
.
int SomeFunctionThatTakes2-IntegerFunction(p2IntFunction pFunc)
{
return pFunc(6, 3);
}

Using them:

void DoNothing(void)
{
// y''all thought I was playin'', huh?
}
.
int Div2(int x, int y)
{
return (x / y);
}
.
pVoidFunction pvFunc = DoNothing;
p2IntFunction iOp = Div2; // integer operation
.
SomeFunctionThatTakesVoidFunction(pvFunc);
SomeFunctionThatTakes2-IntegerFunction(iOp);

Happy Hacking!

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
guitarman310    122
Some of my OpenGL code looks like this:
  

void Render(void (*func)(void))
{
// clear screen etc, etc...

// call needed OpenGL commands

// call my function

if (func != NULL)
func();
}


If I don''t want to use the function, I pass NULL as the parameter. It works good for me.

  
#define JESUS 1

Share this post


Link to post
Share on other sites
CommanderXXL    122
Hmm, it still doesn''t work, maybe it is not possible to do what i''m trying to do. I want to do exactly the following:



class THREAD {...};
class WORLD {...};
THREAD *Thread = new THREAD;
WOLRD *World = new WORLD;

HANDLE THREAD::Create(void (*ThreadFunc)(...))
{
HANDLE ThreadID;
DWORD lpThreadId;

ThreadID = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&lpThreadId);

ThreadCount++;
return ThreadID;
}

int WINMAIN ()
{
Thread->Create((void *)&World->Load("Level.dat"));
}



So my Problem is, that i have a thread class which takes a function Pointer as argument and is supposed to create a thread with exactly this function. And i have World, which is a Pointer to my world class. World has a function for loading a level. This function takes very long and i want to render a Loading screen during my thread runs and the level is loaded.
So i think my problem is the WINMAIN function call which results in a compiler error "& needs lValue" but i have no other ideas how i can get the pointer to the function instead of the return value of my world-load to be given to my thread create routine.

By CommanderXXL

----------------------------
By CommanderXXL
Commander@bredlmuc.de
----------------------------

Share this post


Link to post
Share on other sites
Shannon Barber    1681
It's possible - just more complicated.
What you want is a method pointer (not just a function pointer).
And you want a method pointer that will work with different classes.
Ultimately you want creating a thread out of a method to be easy - so did I, here's my code:
      
template <typename ParentClass>
class CThread
{
public:
CThread() : m_hThread(0), m_dwID(0), m_pParentClass(0)
{
}

~CThread()
{
if(m_hThread)
{
_assert(m_hThread==0); //Thread handle was destroyed prior to terminating the thread, call Exit first

Exit();
}
}

typedef UINT (ParentClass::*MethodProc)(void);
CEvent m_evExit;

BOOL Create(ParentClass* pThis, MethodProc pThreadMethod)
{
//Don't call create twice!

_assert(!m_hThread);

m_pParentClass = pThis;
m_pMethodProc = pThreadMethod;
m_hThread = CreateThread(NULL, NULL, &DefaultProc, this, 0, &m_dwID);

_assert(m_hThread);

return(!m_hThread);
}

BOOL Exit(DWORD dwTime_ms=5000)
{
CLock<> AutoLock(&m_csLock);

if(m_hThread)
{
m_evExit.Signal();
if(WaitOn(dwTime_ms))
return Terminate();
else
return Close();
}
else
{
_assert(m_hThread);
return 0;
}
}

BOOL Suspend()
{
if(m_hThread)
return (0xFFFFFFFF==SuspendThread(m_hThread));
else
{
_assert(m_hThread);
return 0;
}
}

BOOL Resume()
{
if(m_hThread)
return (0xFFFFFFFF==ResumeThread(m_hThread));
else
{
_assert(m_hThread);
return 0;
}
}

BOOL SetPriority(int iPriority)
{
return SetThreadPriority(m_hThread, iPriority);
}
protected:
static unsigned long __stdcall DefaultProc(void* pv)
{
_assert(pv);
return reinterpret_cast<CThread*>(pv)->Run();
}
UINT Run()
{
try
{
_assert(m_pParentClass);
if(m_pParentClass)
{
return (m_pParentClass->*m_pMethodProc)();
}
}
catch(...)
{
_assert(0);
}

return -42;
}
MethodProc m_pMethodProc;
ParentClass* m_pParentClass;

BOOL WaitOn(DWORD dwTime_ms)
{
return (WAIT_OBJECT_0!=WaitForSingleObject(m_hThread, dwTime_ms));
}

BOOL Close()
{
BOOL bClose = CloseHandle(m_hThread);
m_hThread=0;
return(bClose);
}

BOOL Terminate()
{
BOOL bDead;

CLock<CCriticalSection> AutoLock(&m_csLock);

if(m_hThread)
{
if(bDead = TerminateThread(m_hThread, -42))
return Close();
else
return bDead;
}
else
{
_assert(m_hThread); //Shouldn't terminate the thread if it doesn't exist

return 0;
}
}

protected:
HANDLE m_hThread;
DWORD m_dwID;
CCriticalSection m_csLock;
};


CCriticalSection is a simple OO wrapper for dealing with critical sections, same with CEvent, and _assert is a self-written macro (since it's a somewhat of a bad idea to use the C run-time functions in worker threads. (the _ASSERT macro will exhibit undefined behavior for example)

I almost forgot, this is how to use it:

        
class CMyClass
{
CMyClass()
{
_assert(m_thrWorkder.Create(this, Worker));
}
CThread<CMyClass< m_thrWorker;
UINT Worker();
};




I think it may be possible to bind parameters as well using functors, but get this working first. Store the file you want to load in a property of the class...


Magmai Kai Holmlor

"Oh, like you've never written buggy code" - Lee

"What I see is a system that _could do anything - but currently does nothing !" - Anonymous CEO

Edited by - Magmai Kai Holmlor on December 15, 2001 7:43:49 PM

Share this post


Link to post
Share on other sites
LilBudyWizer    491
Depending on what you are doing you might be able to just pass a pointer to a class and it might be more appropriate. You just inherit off a common base class and use a virtual method declared in the base class. The parameter is then a pointer to the base class. When you call the method you pass a pointer to the derived class. The method then calls the method in the base class which actually calls the implementation of the virtual method in the class the pointer actually points to. A pointer to class can always be used as a pointer to a class it is derived from. It is going the other direction that is difficult. When you think function pointer your next thought should always be polymorphism. I can''t think of any situation in C++ that you cannot use polymorphism in place of a function pointer though given time I''m sure I would think of a few where a function pointer was easier.

Share this post


Link to post
Share on other sites
Fruny    1658
quote:
Original post by CommanderXXL
int WINMAIN ()
{
Thread->Create((void *)&World->Load("Level.dat"));
}





This is a common and most annoying problem : you cannot pass member function pointers to functions expecting a function pointer to do a callback.

Here is the canonical solution :

    
class Thread
{
friend void ThreadStartFunc( void* );
parameter_t thread_params;
public:
void Start( parameter_t params ) // call to start the thread

{
thread_params = params;
CreateThread(NULL,0,(ThreadStartFunc ,this,0,&lpThreadId);
};
protected:
virtual void Run() = 0; // the thread's function is implemented in a derived class;

};

void
ThreadStartFunc( void* ptr )
{
Thread* thread = (Thread*) ptr;
ptr->Run();
}


You'd have to actually adjust the return types (for ThreadStartFunc and Run) to what CreateThread() expects.

And remember that you must use _beginthread() if you want to use the C library.

Edited by - Fruny on December 15, 2001 11:59:41 PM

Share this post


Link to post
Share on other sites
CommanderXXL    122
All righty then. I think i can put all this together to make my Threadmanager work. Thanks for all your help.

By CommanderXXL

----------------------------
By CommanderXXL
Commander@bredlmuc.de
----------------------------

Share this post


Link to post
Share on other sites