Sign in to follow this  
Coder88

Function Pointers

Recommended Posts

Welcome all =] In a recent thread I said that am designing a multi-threaded core for my code lib, the way I made it is as follows: * The user can Create two types of Threads: Master threads or Dedicated Threads, the two are separate. Master Threads - Live as long as the core object and once created can't be deleted or added. The user can cpecify how many to create or let the system decide based on cpu core count. (created on core initialization) Dedicated Threads - Can be created anytime and deleted whenever the user wants. Execute the task assigned be the user only once finished thread terminates. * The master threads use a queue system, there is a global Thread system class that manges both thread types. The system thread class contains global queue task list. When a user adds a task to the list it will be scheduled on one of the master threads, NOW HERE COMES THE FUNCTION POINTER QUESTION: My current function pointer that the AddTask() accept is:
void * (*TskPtr)(void**)(void**) 
Is this a good default function pointer? or should i use a different default function pointer for the tasks ?, or allow a couple of different ones although I have an idea how to do it, it will introduce some overhead in assigning tasks, as the master thread only gets a new task from the global task list if it signals it has nothing to do =]. if anyone has suggestions they will be more than welcomed. The Tasks can be anything the user wants. Also is this a good system? or there is a better way to do it ? Improvements ? Criticism and suggestions welcomed. Note: Am using visual studio 2008 pro, C plus plus - the plus signs don't show :( the core is a dll file linked to the application at runtime Thank you.

Share this post


Link to post
Share on other sites
If you're using C++ you should create a Task interface (ie. class with no members and only pure virtual functions), and allow users to extend this interface rather than using a function pointer. The Task interface would require users to implement a method called Run. In addition Run does not need parameters, as the user can give their concrete Task a constructor to simulate passing parameters to Run. This system would be much more flexible than a function pointer. (As for using boost, I don't think this is a complex enough use of function pointers to need it).

Share this post


Link to post
Share on other sites
I don't use function pointers for my task queue; I use an interface (pretty much exactly how sphen_lee described above!):
class IRunnable
{
public:
virtual ~IRunnable() {}
virtual void Run() = 0;
};

This also lets you pass parameters to functions by storing the parameters inside an instance of a Runnable class:
class TaskManager
{
public:
static void AddToQueue( IRunable& );
};

class MyTask : public IRunnable
{
public:
MyTask( int i ) : m_Value(i) {}
virtual void Run()
{
printf( "%d", m_Value );
}
private:
int m_Value;
};

TaskManager::AddToQueue( *(new MyTask(42)) );

Share this post


Link to post
Share on other sites
Quote:
Original post by TheColonial
You're using C++, yet are still using void* ??

You should be slapped :)


Yeah sure..... =], what is wrong with void*, since it can point to anything ?? alternative ?


sphen_lee thanks for the advice I will look into it =] it will be more flexible I didn't thought of that =] before.

Hodgman thanks on an idea how to get started becuase iwas about to post asking for example.


fpsgamer I will look into boost libraries, they seem as something i should know how to use since i heard about it for a long time but never check it out now its the time.

Thanks for all replies and suggestions, if any of the people did their multi-core engines and want to share some of their ideas or thoughts, general structures they used, they will be more than welcomed.

Thanks all.

Share this post


Link to post
Share on other sites
Quote:
Original post by Coder88
Quote:
Original post by TheColonial
You're using C++, yet are still using void* ??

You should be slapped :)


Yeah sure..... =], what is wrong with void*, since it can point to anything ?? alternative ?



That's precisely the problem: it can point to anything! When you use void* you lose any type safety guarantees the compiler can give you. The alternative is to use an interface like Hodgman has shown, which allows users to pass any kind of data without losing type safety.

Share this post


Link to post
Share on other sites
Quote:
Original post by sphen_lee
Quote:
Original post by Coder88
Quote:
Original post by TheColonial
You're using C++, yet are still using void* ??

You should be slapped :)


Yeah sure..... =], what is wrong with void*, since it can point to anything ?? alternative ?



That's precisely the problem: it can point to anything! When you use void* you lose any type safety guarantees the compiler can give you. The alternative is to use an interface like Hodgman has shown, which allows users to pass any kind of data without losing type safety.



Maybe its me, but sometimes i use void becuase i just don't know the type that will be passed and don't always need the overkilll design of OOP for simple tasks.

Also I think if the void* pointers are used right for the right job and with responsibility than its ok.

Share this post


Link to post
Share on other sites
Quote:
Maybe its me, but sometimes i use void becuase i just don't know the type that will be passed and don't always need the overkilll design of OOP for simple tasks.
Do you mean using void* for routines that can support multiple types of parameters? This is where templates should be used.

If you need to actually know the data type, this is where RTTI should be used.

void* is not needed in the above situations.

Quote:
Also I think if the void* pointers are used right for the right job and with responsibility than its ok.
Agreed. I personally have only needed to use it a few times--Not in any application software or video games, though, as it is never needed.

Share this post


Link to post
Share on other sites
Quote:
Original post by Crypter
Quote:
Maybe its me, but sometimes i use void becuase i just don't know the type that will be passed and don't always need the overkilll design of OOP for simple tasks.
Do you mean using void* for routines that can support multiple types of parameters? This is where templates should be used.

If you need to actually know the data type, this is where RTTI should be used.

void* is not needed in the above situations.

Quote:
Also I think if the void* pointers are used right for the right job and with responsibility than its ok.
Agreed. I personally have only needed to use it a few times--Not in any application software or video games, though, as it is never needed.


I used the void* for the function pointer since when i tired with templates it would not Link since its in a dll file or it would not work as expected. Anyway than i choose to use void* since i knew how to work with them quite well and it allowed me to use many types with a generic signature until the task interface was presented to me. as for the templates for other things such as args etc... i use them since they work very well.

As you mentioned I rarely use the void* since as sphen_lee has said the type safety is lost.

Share this post


Link to post
Share on other sites
A solution that is far superior to anything involving void* has already been suggested by fpsgamer. In fact it's similar to Hodgman's suggestion too, but much easier to use.

Here's how it works:


// some function declarations
void my_func();
double do_stuff(double, const string &s);

// some class definitions
class A
{
public:
void do_it() const;
void do_it_another_way(bool useLasers);
};

class B
{
public:
bool operator() () const; // callable
void operator() (int n); // callable with int argument
};

// ...

// Now for the magic. We would like to be able to use each of the above
// functions/functors as tasks in a uniform fashion

// declare a generic functor that takes no arguments and returns void
function<void ()> f;

f = my_func; // now f() will call my_func()
f = bind(do_stuff, 123.0, "Hello!"); // f() calls do_stuff(123.0, "Hello!");

A a;
f = bind(A::do_it, a); // f() calls a.do_it() on a copy of a
f = bind(A::do_it, ref(a)); // f() calls a.do_it() on a itself
f = bind(A::do_it_another_way, ref(a), true); // f() calls a.do_it_another_way(true) on a

B b;
f = b; // f() calls b2(), where b2 is a copy of b
f = bind(b, 5); f() calls a b2(5) where b2 is a copy of b


Note that some of the functions/functors that have been assigned to f originally returned something other than void. function<void ()> will simply discard the return values.

This is only scratching the surface. boost::function can be used to create functors that take and return types of any kind and bind can be used to bind only some of the arguments. You don't need void *. You don't need to manually create an inheritance hierarchy. You don't need to break a sweat. Do yourself a favor and look closer at fpsgamer's suggestion. All this void* chatter is moot.

Share this post


Link to post
Share on other sites

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