boost::bind and multithreading questions *solved

Started by
6 comments, last by thedustbustr 15 years, 9 months ago
im currently trying to do some multithreading in my 3d engine... the way i want to do it is with somekind of functor system where i ONLY send functors to a queue in my render thread... this way i only have to lock the queue when communicating between the threads... it works something like this... Resource textureid= CreateTexture("asdasd"); // this sends a functor to the render thread and returns a copy of the textures ID... soo it doesnt actually send back the texture object that was created in the render thread just its id... now if i want to do something with this outside of the render thread i would send a functor and and the id of the object that it should run this on... for example QueueCommand(boost::bind(&Texture::SetWidth, _1, 1000), textureid); // now when the renderer reads this it will first find the item which the id "textureid" is representing... and then run the function on that item my first questions is if this is a good system? secondly how would i get this part working renderer->QueueCommand(boost::bind(&Texture::SetWidth, _1, 1000), textureid); what kind of "boost::function" would boost::bind(&Texture::SetWidth, _1, 1000) give? and how do i make an object to run this? somehow i would have to send the real object at the place of the "_1" EDIT: clearified a bit [Edited by - Dragon_Strike on July 28, 2008 12:41:51 AM]
Advertisement
Quote:what kind of "boost::function" would boost::bind(&Texture::SetWidth, _1, 1000) give? and how do i make an object to run this? somehow i would have to send the real object at the place of the "_1"


Look at how boost::asio does it. You may find that storing boost::bind's results is an incredibly convoluted task, which requires plenty of trickery through use of wrapper objects, polymorphic invocations and desturctors.

Alternative, is to provide a generic wrapper to boost functions:
struct Invocation {  virtual void invoke() = 0;};template < class Handler >struct FunctorInvocation {  virtual void invoke()  {    h();  }  Handler h;};


The pre-requisite for this is that Handler object has operator()(), which should be the case with boost::bind's results.

Your queue is then std::deque<Invocation *>. Note that this will result in considerable number of heap allocations for each invocation, as well as added overhead from virtual calls. So you may want to use such calls sparingly.

Quote:what kind of "boost::function" would boost::bind(&Texture::SetWidth, _1, 1000) give? and how do i make an object to run this? somehow


template < class Handler >
void QueueCommand(Handler h);

QueueCommand( boost::bind(&Texture::SetWidth, textureptr, textureid, 1000) );
Quote:You may find that storing boost::bind's results is an incredibly convoluted task, which requires plenty of trickery through use of wrapper objects, polymorphic invocations and desturctors.


void QueueCommand(boost::function<void ()> h);

QueueCommand( boost::bind(&Texture::SetWidth, textureptr, textureid, 1000) );

what did I miss?
Quote:what kind of "boost::function" would boost::bind(&Texture::SetWidth, _1, 1000) give? and how do i make an object to run this? somehow i would have to send the real object at the place of the "_1"


boost::function<void (int)> fn = boost::bind(&Texture::SetWidth, _1, 1000);fn(750); //Texture::SetWidth(750, 1000);  setwidth thus needs to be a static memberTexture t = new Texture (...);boost::function<void (int)> bound_method = boost::bind(&Texture::SetWidth, t, _1, 1000);bound_method(750); //t->SetWidth(750, 1000);  setwidth is now a method, called on instance t


RTFM. function, bind
Quote:Original post by thedustbustr
Quote:You may find that storing boost::bind's results is an incredibly convoluted task, which requires plenty of trickery through use of wrapper objects, polymorphic invocations and desturctors.


void QueueCommand(boost::function<void ()> h);

QueueCommand( boost::bind(&Texture::SetWidth, textureptr, textureid, 1000) );

what did I miss?


The case where your functions cannot be represented with single sugnature, such as void().

And still, using boost function in this way results in terrible overhead. Without using custom allocation for functors it's far from negligible, and even with custom allocators, it requires about 10 times more work than virtual functions or function pointers.

As an example, the boost::bind I used for networking, at fully loaded (100 Mbps) nop server (just checks the size of packet) takes 60-80% of cpu, pre-allocated boost function 10-30%, and regular function pointer 0-5%, equivalent to revc+select with char * pointer.

I usually avoid blanket performance statements, but for frequent calls (20,000 per second - which isn't even that many), boost functions are, put plainly, horrible. That's also the reason why boost::signal is all but useless for such cases.

The price you pay for generic approach in this case is really high, and rarely needed. Or at very least, there's very accessible alternatives.
I don't really care about the performance argument, as most usage of boost::function can be converted to native c++ function pointers with hardly any effort, should this code actually become a bottleneck.

Could you elaborate more on the part about objects where parameters aren't known at time of binding? It seems to me that there is no need to support arbitrary signatures - all signatures would be consistent - if we are queueing up tasks for future invocation, all parameters would be known at queue time, except for generic parameters which might be passed to everything, like a deltatime or something. I guess I don't see a use case for anything but nullary invokable tasks.

Even if there were, I don't see how the code you posted would facilitate in solving this problem.
ok this is what i want to do...

lets say i have a class "Factory" and want to call a function in it... but i cant decide which factory instance should run this is in the current thread...

soo if i wanted to create a functor for...

factory->DoSomething(10); // no return

i would do something like

boost::function<???> func = boost::bind(&Factory::DoSomething, _1, 10); // where _1 is the item which the function should be called for...

my question is.. when i know what factory instance should run this functor.. how do i call it? and what type should the boost::function have?

func(&factory); or something?




I answered this question above in this thread.

This topic is closed to new replies.

Advertisement