Jump to content
  • Advertisement
Sign in to follow this  
ZealousEngine

Is it possible to buffer/delay function calls?

This topic is 4032 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

Lets say I have two threads, A and B. If I want thread A to manipulate a object that exists on thread B, I have a couple options.. 1.) I could lock the object from thread A. Of course this is not the best solution, because it will stop thread B in its tracks. 2.) Implement a lockless message que/buffer inbetween the two threads. This way thread A can send requests to thread B, and when thread B receives those requests, it will manipulate the object accordingly. The main problem with this solution is - if the object we are trying to access on thread B is complex (with many methods), we will need to write a equally complex que/buffer in order to get at all the functionality. This could result in a LOT of extra work (potentially a message que that is as complex as the object itself!). Which brings me to my question. Is THIS possible... 3.) From thread A, record a list of all the function calls that you WANT to perform on the object, then send this 'list of commands' (via a message que) to thread B. Once the list arrives on thread B, thread B executes the list of commands. This would solve the main problem with solution number two, in that you no longer have to write a complex message que to simulate all the functionality of the object youre trying to access. You can now directly access a object that exists on thread B, FROM thread A. You just do it in a delayed/buffered fashion. Now of course any method that RETURNS data would have to be sent back via another message que, but thats not a big deal because I plan on writing to this particular object MUCH more than I plan on reading from it. So, to recap. Lets say thread B has a object called myObject, with a method foo(). How can I (from thread A) write something to the effect of... commandList.push_back( myObject.foo() ); Then PASS this list of commands to thread B, where it will be executed. Thanks in advance! *also note, we are assuming 'myObject' is closed source. So I cant just implement the 'buffered' functionality into the object itself. And we are working with C++. [Edited by - ZealousEngine on May 8, 2007 1:49:34 AM]

Share this post


Link to post
Share on other sites
Advertisement
(assuming C++ because of the push_back call)

Couldn't you just make an array of pointers to member functions and send that? That would solve the issue with the complex interface in 2 too.

Share this post


Link to post
Share on other sites
You mean send pointers to the member functions BACK to thread A? But then it would not be safe to USE those pointers from thread A (we cant assume thread B isnt reading from part of the object).

Share this post


Link to post
Share on other sites
Don't try and put the actual method-pointers/functors on a queue, make an enum instead, and stick a switch into thread B.

commandList.push_back(CMD_FUNCTIONA);

and in thread B
switch(*commandListIter)
{
case CMD_FUNCTIONA: break;
case CMD_FUNCTIONB: break;
default: ScreamLoudly(); break;
}

or something like that.
You will of course have to synchronize reading/writing to the command-list, but you'll never get away from that.
Trying to do this with functors is just a lot of unnecessary hassle.

Share this post


Link to post
Share on other sites
Hmm but making a switch like that could be very complex (if its going to match up 1 to 1 with the functionality of the object).

What im talking about is a way to write a custom block of code, pass it to another thread, then 'execute' it said block of code on that thread.

BTW what is a functor?

Share this post


Link to post
Share on other sites
Ok so im reading up on functors, it looks like they would work right? I mean I could say (from thread A)...

commandList.add( &myObj, Object::foo(), parms_If_Any );

Pass the commandList to thread B, where (if im understanding functors correctly), it can call foo() on object myObj and pass in the parms I specified (if any).

Eh?

Share this post


Link to post
Share on other sites
Quote:
Original post by tok_junior
Don't try and put the actual method-pointers/functors on a queue, make an enum instead, and stick a switch into thread B.

commandList.push_back(CMD_FUNCTIONA);

and in thread B
switch(*commandListIter)
{
case CMD_FUNCTIONA: break;
case CMD_FUNCTIONB: break;
default: ScreamLoudly(); break;
}

or something like that.
You will of course have to synchronize reading/writing to the command-list, but you'll never get away from that.
Trying to do this with functors is just a lot of unnecessary hassle.


Hmm Writing a big switch statement is just a lot of unnecessary hassle (not to mention brittle). Just use a container of boost::function<void()>s, and use boost::bind to create the functors you want to execute later, if you even need to do that.

For example:
commandList.push_back( boost::bind( &MyObjectType::foo, &myObject ) );

commandList is of type:

std::vector< boost::function<void()> >

Or similar.

The Boost C++ Libraries

Also, a library like (boost) Asio can help handle syncronization issues. It's not core [boost], and still under development, but it works, and accomplishes what it's meant to.

Share this post


Link to post
Share on other sites
Good so it sounds like this is pretty simple/common problem? I have ZERO experience with functors, but I LOVE boost. So boost::bind is in essence a boost version of a functor? Can I pass parms with bind? Ill have to do some research on it...

And I have synchronization under control (that part is super easy imo).

Share this post


Link to post
Share on other sites
Quote:
Original post by ZealousEngine
Good so it sounds like this is pretty simple/common problem?


The more generalized problem -- storing function calls/actions to be performed later -- is fairly common. This has all sorts of possible applications -- from undo systems (by storing the acts needed to undo a given transformation), to GUI systems (by providing the OO equivilant of callbacks -- that is, the ability to store a function to be called when, say, a button is clicked).

Quote:
I have ZERO experience with functors, but I LOVE boost. So boost::bind is in essence a boost version of a functor?


Almost. It is a function which returns a functor -- a functor "factory" if you will. It makes it easy as 1-2-3 to make functors without the tedium of writing all the boilerplate yourself (which is still pretty minimal).

boost::function on the other hand is a functor which can store other functors of varying types very easily (which is handy when you want to store different functors to represent different calls/actions, as is usually the case).

Quote:
Can I pass parms with bind?


Yes.

Quote:
And I have synchronization under control (that part is super easy imo).


Glad to hear :-).

Share this post


Link to post
Share on other sites
Awesome! Thanks for all the good news. Im gonna do some research on boost bind, and maybe start converting my project today!

Up to this point, whenever I wanted to access some part of a object that existed in another thread, I had to write a CUSTOM message que (what a pain!). Now I can 'access' these same objects from ANYWHERE by passing a list of access requests to the objects 'home thread'. Once on the home thread, the access request list will be executed only when it is safe to do so.

HOORAY FOR FUNCTORS!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!