If overlapping compute and I/O is important, then perhaps something akin to the "GUI Thread" pattern in the TBB design patterns manual might work, where the GUI thread is replaced by an I/O thread.
So basically (in the case of file or network I/O) I create my own thread, and use (something like) a tbb::concurrent_bounded_queue to move data between it and the producer or consumer task?
Or is your point to use the task::enqueue method as a way of kicking off asynchronous work?
Also, if you do mean I should create my own native thread, does TBB expose a platform-neutral thread library?
The TBB documentation should have a list of classes that are thread-safe using non-TBB threads. Principally you want to know if the class interacts with the TBB thread scheduler. If it does, then assume it is unsafe for use by your non-TBB threads. The tbb::concurrent_bounded_queue may or may not be safe dependent upon which thread may cause the queue to grow or shrink as well as other issues such as a fair lock (or any lock that can cause the current thread to task steal). I haven't looked into this, maybe one of the other regulars can point you to documentation regarding this information. You can roll your own queue relatively easily. A ring buffer is often all that is required (with first fill starting/resuming non-TBB thread dedicated to I/O task).
There are other threading tools that handle I/O tasks. Pardon a plug here, but QuickThread (www.quickthreadprogramming) offers two classes of thread pools: Compute class and I/O class. The compute class is similar to the purpose of TBB thread pool. The I/O class is there specifically for requirements as your own. So there would be little need to create and manageyour own threads. You can have any number of I/O class threads. The compute class tends to work best when limited to the number of logical processors available to the process (default setting).
task::enqueue is good way to kick off work that should not run on a user-created thread. For example, you can use TBB's std::thread to create an I/O thread and want a task to run when some I/O action completes. The I/O thread can do the I/O operation and then use task::enqueue to fire off the task.If the I/O thread needs to wait on the task to complete, consider using std::condition_variable to make it wait, which is in include/tbb/compat/condition_variable. That way the I/O thread blocks while it is waiting and does not waste cycles.
The general strategy is to use threads for control flow that is usually blocked, and tasks for control flow that is usually busy. task::enqueue and condition_variable provide ways to transfer control between the two domains.
TBB 3.0 exposes std::thread. It's defined in include/tbb/compat/thread and fairly close to the C++1x draft std::thread. The significant differences are where time units are requred. Our version uses tbb::tick_count::interval_t because we did not want to recreate the C++1x std::chrono facilities. (We had to stop somewhere, or transitive closure would force us to write a full C++1x library :-)
That's good to know. Is there decent documentation anywhere about the ways in which TBB's std::thread differs from a fully compatible C++0x std::thread?