It's a bit complicated to do on Mac OS X/Linux.
Why?
Both operating systems support threads. Both support semaphores or condition variables. That's really all you need.
In the very, very, very easiest case (you can make it much more sophisticated, of course), the render thread will write requests (a function pointer and an argument like pointer to a file name) to an array. Then it increments the semaphore by the number of items, so the loader thread wakes up and knows how many items to process. It doesn't need to use async I/O at all, on the contrary... blocking is mighty fine (far fewer problems and far less system-dependent low level crap, and no surprises like async ops suddenly running synchronously).
When it is done loading the last asset in the scene/level, it signals a condition variable, or a second semaphore, or it could simply set a boolean flag in an entirely thread-unsafe manner (it doesn't really matter, the worst thing to happen would be that the render thread picks it up a bit later).
The render thread keeps rendering and checks the boolean flag (or condition variable) at the end of every frame. Eventually the flag will become true (or the condvar will), so you know that the data is now ready to be used in the next frame.
Yes... a proper solution is much more evolved (the infamous "resource manager"), but if your problem is really just loading a complete level and not willing to skip redraws during those 10 seconds, then you can do this in like 10-15 lines of code, with a minimum set of needed OS functionality.