Replace _waitVar.notify_one() with _waitVar.notify_all(). This was the
only hurdle to documenting ConcurrentQueue::waitAll() as thread-safe.
ConcurrentQueueTest::waitAllFromMultipleThreads() passes instead of
hanging now.
ConcurrentQueueTest::cancelPending1UserThread() often fails when
ConcurrentQueueTest is launched from Qt Creator immediately after
switching between Debug and Release YACReader build configurations.
The CPU busyness must be affecting the thread scheduling timing, which
breaks the test's timing assumptions in this case.
Use the return value of ConcurrentQueue::cancelPending() instead of
relying on the timing of thread scheduling to determine the number of
canceled jobs.
The return value can be used to make
ConcurrentQueueTest::cancelPending1UserThread() non-flaky. It may also
be useful to non-testing code.
Improve the performance of cancelPending() by locking the two mutexes
separately and minimizing the locking time.
Worker threads may well be executing jobs while this function is being
called. If ConcurrentQueue::waitAll() is called soon enough after
cancelPending(), the worker threads may still be running, but waitAll()
would return immediately as jobsLeft would be nonpositive.
Subtracting _queue.size() from jobsLeft sets this variable to the number
of worker threads that are executing jobs at the moment.
ConcurrentQueueTest::cancelPending1UserThread() passes most of the time
now. But it still fails occasionally because it depends on the timing of
thread scheduling, which is unreliable.
Place common Qt Test qmake code into tests/qt_test.pri.
Build tests as part of top-level YACReader project unless no_tests
CONFIG option is set. This way the tests are built by default during
development. Packagers can skip building tests by running
`qmake "CONFIG+=no_tests"`.
Both ConcurrentQueueTest::singleUserThread() and
ConcurrentQueueTest::multipleUserThreads() pass. Evidently
ConcurrentQueue::enqueue() can be safely called from multiple threads on
the same ConcurrentQueue object with no additional synchronization. Once
each thread enqueues all its jobs, one thread can safely call waitAll().