4

I am doing some development trying out C++11 threads. I would like to run some code in an asynchronous thread and when that code is done I would like to run other code on the main thread But only when it's done!

This is because the things I would like to run async is loading OpenGL stuff, and it's a bit tricky with the OpenGL contexts when doing threads, as far as I know it's pretty much a don't run the same context in different threads.

However I would like to create a loader thread, which loads collada files and the time consuming stuff here really is to parse the file and set up the data and all of that I could (technically) do in a separate thread and then just do the opengl specific tasks on the main thread. (this is my initial thought and I might just be going at it the wrong way)..

So I am thinking that if I could detach one thread async to load up the collada file and fill the out the data, then once it's finished I'll invoke on the main thread to bind buffers, set up shaders and so on. I can do it without threads, but would be pretty smooth to load new data in the background without GL freaking out..

So I'll try to line up the steps I want to do:

  1. Main thread goes around doing what it does...
  2. Someone asks for a new mesh to be loaded
  3. the mesh initialized by creating an async thread and loading inside it the collada data
  4. meanwhile the main thread goes on doing it's stuff
  5. once the collada loading is done the async thread informs the main thread that it wishes to do additional loading (i.e. setup buffers, and so on) ON main thread.
  6. the setting up finishes and the mesh adds itself to a render queue

I do have all of it working synchronous and what I want is a way to do some things once the detached async thread finishes.

Any ideas or of course constructive criticism of my thinking here :P is greeted with a warm welcome! I might be thinking about it all the wrong way, I've been thinking about doing something like an observer pattern but I don't really know how to tackle it the best way. I wouldn't mind threading the OpenGL stuff, but it seem a bit like asking for trouble..

ildjarn
  • 62,044
  • 9
  • 127
  • 211
qrikko
  • 2,483
  • 2
  • 22
  • 35

1 Answers1

6

If I understood your use case correctly, then I think the std::async() function, started with the std::launch::async policy to make sure the operation is really started on another thread, does just what you want:

// Your function to be executed asynchronously
bool load_meshes();

// You can provide additional arguments if load_meshes accepts arguments
auto f = std::async(std::launch::async, load_meshes); 

// Here, the main thread can just do what it has to do...

// ...and when it's finished, it synchronizes with the operation
// and retrieve its result (if any)

bool res = f.get(); // res will hold the return value of load_meshes,
                    // or this will throw an exception if one was
                    // thrown inside load_meshes()

if (res) 
{ 
    // ... and then it will go on doing the remaining stuff on the main thread
}

One tricky thing to be aware of here, is that you should always assign the return value of std::async() to some variable (of type std::future<T>), where T is the type returned by load_meshes(). Failing to do so will cause the main thread to wait until load_meshes() is finished (thus, it's as if the function was invoked in the main thread).

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • It does look promising! I'll try it out, but looks exactlu like what I'm looking for. – qrikko Feb 22 '13 at 23:54
  • 2
    @qrikko: Sorry, I forgot to specify the launch policy as the first argument to `std::async()`. Edited. Without that argument, the implementation is free to decide whether to launch it on a new thread or not. – Andy Prowl Feb 23 '13 at 00:02
  • I did play around with it a bit, and it works as you describe, the thing I had in mind were more of a "call on main thread when ready", since the `f.get();` actually does halt the main thread until it's done I need to keep track of when the async function is done. I however think that your answer really helped me grasp some missing pieces in my understanding, and I think it gives me enough to work it out. – qrikko Feb 23 '13 at 01:22
  • 1
    @qrikko you'll want to send some kind of signal to the main thread in a non-blocking way. Or you could poll the `future` with a `wait_for(0)` and see if that works (in theory, `wait_for(0)` can block as long as it wants, in practice this may work). If you have a bounded number of such tasks, your main "game loop" could check such `future`s on each iteration. Note, however, that some kind of out-of-band communication is often useful, because it lets you do things like abort a load, or shut down the app without waiting for the load to complete... – Yakk - Adam Nevraumont Feb 23 '13 at 01:30
  • 1
    @qrikko: OK, this was something I wasn't sure about: I thought the main thread didn't have anything else to do than the "its stuff" you mention in point 4 :-) If that's not the case, you may consider a polling strategy such as the one suggested by Yakk. Otherwise, if your main thread has a message loop, you may want your loader thread to post a message when done. – Andy Prowl Feb 23 '13 at 01:37
  • Thanks both for those answers! @AndyProwl I can see how that 'description' were a bit miss leading -_- sorry for that. But all in all I am happy for the discussion and the answers I've received I am ending up doing more of a poll solution. It kind of makes sense since the meshes can really be loaded at any time (on top of the application I have a lua-based scripting system which also allows for resource loading, but the actual loading is done through a resource manager, and that manager will now keep track of all of this and it looks like it's doing what I want. so again thanks! – qrikko Feb 23 '13 at 02:16