Skip to main content
GameDev.net gamedev.net
🔒 Locked

Function Pointers as parameters?

Started by CommanderXXL Dec 15, 2001 at 7:27 AM 6 replies 1.4k views
Original Post
CommanderXXL
CommanderXXL
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
---------------------------- By CommanderXXLCommander@bloomm.de----------------------------
Oluseyi
Oluseyi
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!
guitarman310
guitarman310
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
[source]#define JESUS 1[/source]
CommanderXXL
CommanderXXL
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
----------------------------
---------------------------- By CommanderXXLCommander@bloomm.de----------------------------
Shannon Barber
Shannon Barber
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
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
LilBudyWizer
LilBudyWizer
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.
Keys to success: Ability, ambition and opportunity.
Fruny
Fruny
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
"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
CommanderXXL
CommanderXXL
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
----------------------------
---------------------------- By CommanderXXLCommander@bloomm.de----------------------------

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.