I enjoyed the talk, but of course, it doesn't tell the whole picture.
As Herb mentioned, there are basically two ways to deal with shared resources: put a lock around it (mutex), or give the resource "thread affinity" via something like a message queue. Neither one guarantees responsiveness, and if you want your program to clean up gracefully, both will have a "wait" at some point.
Basically, message queues don't guarantee responsiveness because one item in the queue could take a long time, and prevent the other items from being performed in a timely manner. In some applications, this shows up as a pause, followed by a rapid catch up as all the queued up events fire at once. This can be mitigated by splitting up your resources in a more fine grained manner, and putting the "slow" resources on their own threads. You can't just throw a thread pool at the problem though, as then you need to reintroduce mutexes.
As for the graceful cleanup, leaving threads running after main() exits is usually a bad idea. You can also run into problems if your application dynamically loads and unloads shared libraries, and you leave threads running that execute code in the unloaded library. Both of these cases are handled poorly by Herb's "stop message" implementation, at least if any of the messages are slow. You really want to be able to eject all existing items in the queue, and preferably signal the currently running item to stop. Not all apps need to clean up gracefully though.