A multithreaded test coordinates concurrent operations, then checks their results. A ready-and-go barrier lets worker tasks signal that they are prepared before the test releases them to run. section 11.2.5
A robust test coordinates completion and cleanup as well as the start:
- Use std::async with std::launch::async to run each task on its own thread; collect completion through futures. section 11.2.5
- Keep task futures outside the try block. If an exception occurs, release workers waiting for the go signal, then rethrow; future destruction waits for unfinished tasks. section 11.2.5
- Wait for task completion before checking results; a task can return its result through its future. section 11.2.5
Listing 11.1. An example test for concurrent push() and pop() calls on a queue
void test_concurrent_push_and_pop_on_empty_queue()
{
threadsafe_queue<int> q; #1
std::promise<void> go,push_ready,pop_ready; #2
std::shared_future<void> ready(go.get_future()); #3
std::future<void> push_done; #4
std::future<int> pop_done;
try
{
push_done=std::async(std::launch::async, #5
[&q,ready,&push_ready]()
{
push_ready.set_value();
ready.wait();
q.push(42);
}
);
pop_done=std::async(std::launch::async, #6
[&q,ready,&pop_ready]()
{
pop_ready.set_value();
ready.wait();
return q.pop(); #7
}
);
push_ready.get_future().wait(); #8
pop_ready.get_future().wait();
go.set_value(); #9
push_done.get(); #10
assert(pop_done.get()==42); #11
assert(q.empty());
}
catch(...)
{
go.set_value(); #12
throw;
}
}
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":2,\"ch\":60},{\"line\":2,\"ch\":62}],[{\"line\":28,\"ch\":60},{\"line\":28,\"ch\":62}],[{\"line\":29,\"ch\":60},{\"line\":29,\"ch\":62}],[{\"line\":34,\"ch\":60},{\"line\":34,\"ch\":62}],[{\"line\":3,\"ch\":60},{\"line\":3,\"ch\":62}],[{\"line\":4,\"ch\":60},{\"line\":4,\"ch\":62}],[{\"line\":5,\"ch\":60},{\"line\":5,\"ch\":62}],[{\"line\":9,\"ch\":60},{\"line\":9,\"ch\":62}],[{\"line\":17,\"ch\":60},{\"line\":17,\"ch\":62}],[{\"line\":22,\"ch\":60},{\"line\":22,\"ch\":62}],[{\"line\":25,\"ch\":60},{\"line\":25,\"ch\":62}],[{\"line\":27,\"ch\":60},{\"line\":27,\"ch\":62}],[{\"line\":28,\"ch\":60},{\"line\":28,\"ch\":63}],[{\"line\":29,\"ch\":60},{\"line\":29,\"ch\":63}],[{\"line\":34,\"ch\":60},{\"line\":34,\"ch\":63}]]"}
!@%STYLE%@!
The example coordinates concurrent push() and pop() calls on an empty queue, then checks the result. section 11.2.5
