| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #define TEST_NAME "util/threading" |
| #include "util/testing.h" |
|
|
| #include "util/logging.h" |
| #include "util/threading.h" |
|
|
| using namespace colmap; |
|
|
| namespace { |
|
|
| |
| |
| class Barrier { |
| public: |
| Barrier() : Barrier(2) {} |
|
|
| explicit Barrier(const size_t count) |
| : threshold_(count), count_(count), generation_(0) {} |
|
|
| void Wait() { |
| std::unique_lock<std::mutex> lock(mutex_); |
| auto current_generation = generation_; |
| if (!--count_) { |
| ++generation_; |
| count_ = threshold_; |
| condition_.notify_all(); |
| } else { |
| condition_.wait(lock, [this, current_generation] { |
| return current_generation != generation_; |
| }); |
| } |
| } |
|
|
| private: |
| std::mutex mutex_; |
| std::condition_variable condition_; |
| const size_t threshold_; |
| size_t count_; |
| size_t generation_; |
| }; |
|
|
| } |
|
|
| |
| |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadWait) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| endBarrier.Wait(); |
| } |
| }; |
|
|
| TestThread thread; |
| BOOST_CHECK(!thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Start(); |
|
|
| thread.startBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(thread.IsFinished()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPause) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier pauseBarrier; |
| Barrier pausedBarrier; |
| Barrier resumedBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| pauseBarrier.Wait(); |
| pausedBarrier.Wait(); |
| BlockIfPaused(); |
| resumedBarrier.Wait(); |
| endBarrier.Wait(); |
| } |
| }; |
|
|
| TestThread thread; |
| BOOST_CHECK(!thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Start(); |
|
|
| thread.startBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.pauseBarrier.Wait(); |
| thread.Pause(); |
| thread.pausedBarrier.Wait(); |
| while (!thread.IsPaused() || thread.IsRunning()) { |
| std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| } |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Resume(); |
| thread.resumedBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(thread.IsFinished()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPauseStop) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier pauseBarrier; |
| Barrier pausedBarrier; |
| Barrier resumedBarrier; |
| Barrier stopBarrier; |
| Barrier stoppingBarrier; |
| Barrier stoppedBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| pauseBarrier.Wait(); |
| pausedBarrier.Wait(); |
| BlockIfPaused(); |
| resumedBarrier.Wait(); |
| stopBarrier.Wait(); |
| stoppingBarrier.Wait(); |
|
|
| if (IsStopped()) { |
| stoppedBarrier.Wait(); |
| endBarrier.Wait(); |
| return; |
| } |
| } |
| }; |
|
|
| TestThread thread; |
| BOOST_CHECK(!thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Start(); |
|
|
| thread.startBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.pauseBarrier.Wait(); |
| thread.Pause(); |
| thread.pausedBarrier.Wait(); |
| while (!thread.IsPaused() || thread.IsRunning()) { |
| std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| } |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Resume(); |
| thread.resumedBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.stopBarrier.Wait(); |
| thread.Stop(); |
| thread.stoppingBarrier.Wait(); |
| thread.stoppedBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(thread.IsFinished()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadRestart) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| endBarrier.Wait(); |
| } |
| }; |
|
|
| TestThread thread; |
| BOOST_CHECK(!thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| for (size_t i = 0; i < 2; ++i) { |
| thread.Start(); |
|
|
| thread.startBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(thread.IsFinished()); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadValidSetup) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier signalBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| SignalValidSetup(); |
| signalBarrier.Wait(); |
| endBarrier.Wait(); |
| } |
| }; |
|
|
| TestThread thread; |
| BOOST_CHECK(!thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Start(); |
|
|
| thread.startBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.signalBarrier.Wait(); |
| BOOST_CHECK(thread.CheckValidSetup()); |
|
|
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(thread.IsFinished()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadInvalidSetup) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier signalBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| SignalInvalidSetup(); |
| signalBarrier.Wait(); |
| endBarrier.Wait(); |
| } |
| }; |
|
|
| TestThread thread; |
| BOOST_CHECK(!thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.Start(); |
|
|
| thread.startBarrier.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(thread.IsRunning()); |
| BOOST_CHECK(!thread.IsFinished()); |
|
|
| thread.signalBarrier.Wait(); |
| BOOST_CHECK(!thread.CheckValidSetup()); |
|
|
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(thread.IsStarted()); |
| BOOST_CHECK(!thread.IsStopped()); |
| BOOST_CHECK(!thread.IsPaused()); |
| BOOST_CHECK(!thread.IsRunning()); |
| BOOST_CHECK(thread.IsFinished()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestCallback) { |
| class TestThread : public Thread { |
| public: |
| enum Callbacks { |
| CALLBACK1, |
| CALLBACK2, |
| }; |
|
|
| TestThread() { |
| RegisterCallback(CALLBACK1); |
| RegisterCallback(CALLBACK2); |
| } |
|
|
| private: |
| void Run() { |
| Callback(CALLBACK1); |
| Callback(CALLBACK2); |
| } |
| }; |
|
|
| bool called_back1 = false; |
| std::function<void()> CallbackFunc1 = [&called_back1]() { |
| called_back1 = true; |
| }; |
|
|
| bool called_back2 = false; |
| std::function<void()> CallbackFunc2 = [&called_back2]() { |
| called_back2 = true; |
| }; |
|
|
| bool called_back3 = false; |
| std::function<void()> CallbackFunc3 = [&called_back3]() { |
| called_back3 = true; |
| }; |
|
|
| TestThread thread; |
| thread.AddCallback(TestThread::CALLBACK1, CallbackFunc1); |
| thread.Start(); |
| thread.Wait(); |
| BOOST_CHECK(called_back1); |
| BOOST_CHECK(!called_back2); |
| BOOST_CHECK(!called_back3); |
|
|
| called_back1 = false; |
| called_back2 = false; |
| thread.AddCallback(TestThread::CALLBACK2, CallbackFunc2); |
| thread.Start(); |
| thread.Wait(); |
| BOOST_CHECK(called_back1); |
| BOOST_CHECK(called_back2); |
| BOOST_CHECK(!called_back3); |
|
|
| called_back1 = false; |
| called_back2 = false; |
| called_back3 = false; |
| thread.AddCallback(TestThread::CALLBACK1, CallbackFunc3); |
| thread.Start(); |
| thread.Wait(); |
| BOOST_CHECK(called_back1); |
| BOOST_CHECK(called_back2); |
| BOOST_CHECK(called_back3); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestDefaultCallback) { |
| class TestThread : public Thread { |
| public: |
| Barrier startBarrier; |
| Barrier signalBarrier; |
| Barrier endBarrier; |
|
|
| void Run() { |
| startBarrier.Wait(); |
| endBarrier.Wait(); |
| } |
| }; |
|
|
| bool called_back1 = false; |
| std::function<void()> CallbackFunc1 = [&called_back1]() { |
| called_back1 = true; |
| }; |
|
|
| bool called_back2 = false; |
| std::function<void()> CallbackFunc2 = [&called_back2]() { |
| called_back2 = true; |
| }; |
|
|
| TestThread thread; |
| thread.AddCallback(TestThread::STARTED_CALLBACK, CallbackFunc1); |
| thread.AddCallback(TestThread::FINISHED_CALLBACK, CallbackFunc2); |
| thread.Start(); |
| thread.startBarrier.Wait(); |
| BOOST_CHECK(called_back1); |
| BOOST_CHECK(!called_back2); |
| thread.endBarrier.Wait(); |
| thread.Wait(); |
| BOOST_CHECK(called_back1); |
| BOOST_CHECK(called_back2); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolNoArgNoReturn) { |
| std::function<void(void)> Func = []() { |
| int num = 0; |
| for (int i = 0; i < 100; ++i) { |
| num += i; |
| } |
| }; |
|
|
| ThreadPool pool(4); |
| std::vector<std::future<void>> futures; |
|
|
| for (int i = 0; i < 100; ++i) { |
| futures.push_back(pool.AddTask(Func)); |
| } |
|
|
| for (auto& future : futures) { |
| future.get(); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolArgNoReturn) { |
| std::function<void(int)> Func = [](int num) { |
| for (int i = 0; i < 100; ++i) { |
| num += i; |
| } |
| }; |
|
|
| ThreadPool pool(4); |
| std::vector<std::future<void>> futures; |
|
|
| for (int i = 0; i < 100; ++i) { |
| futures.push_back(pool.AddTask(Func, i)); |
| } |
|
|
| for (auto& future : futures) { |
| future.get(); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolNoArgReturn) { |
| std::function<int(void)> Func = []() { return 0; }; |
|
|
| ThreadPool pool(4); |
| std::vector<std::future<int>> futures; |
|
|
| for (int i = 0; i < 100; ++i) { |
| futures.push_back(pool.AddTask(Func)); |
| } |
|
|
| for (auto& future : futures) { |
| future.get(); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolArgReturn) { |
| std::function<int(int)> Func = [](int num) { |
| for (int i = 0; i < 100; ++i) { |
| num += i; |
| } |
| return num; |
| }; |
|
|
| ThreadPool pool(4); |
| std::vector<std::future<int>> futures; |
|
|
| for (int i = 0; i < 100; ++i) { |
| futures.push_back(pool.AddTask(Func, i)); |
| } |
|
|
| for (auto& future : futures) { |
| future.get(); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolStop) { |
| std::function<int(int)> Func = [](int num) { |
| for (int i = 0; i < 100; ++i) { |
| num += i; |
| } |
| return num; |
| }; |
|
|
| ThreadPool pool(4); |
| std::vector<std::future<int>> futures; |
|
|
| for (int i = 0; i < 100; ++i) { |
| futures.push_back(pool.AddTask(Func, i)); |
| } |
|
|
| pool.Stop(); |
|
|
| BOOST_CHECK_THROW(pool.AddTask(Func, 100), std::runtime_error); |
|
|
| pool.Stop(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolWait) { |
| std::vector<uint8_t> results(100, 0); |
| std::function<void(int)> Func = [&results](const int num) { |
| results[num] = 1; |
| }; |
|
|
| ThreadPool pool(4); |
| pool.Wait(); |
|
|
| for (size_t i = 0; i < results.size(); ++i) { |
| pool.AddTask(Func, i); |
| } |
|
|
| pool.Wait(); |
|
|
| for (const auto result : results) { |
| BOOST_CHECK_EQUAL(result, 1); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolWaitEverytime) { |
| std::vector<uint8_t> results(4, 0); |
| std::function<void(int)> Func = [&results](const int num) { |
| results[num] = 1; |
| }; |
|
|
| ThreadPool pool(4); |
|
|
| for (size_t i = 0; i < results.size(); ++i) { |
| pool.AddTask(Func, i); |
| pool.Wait(); |
|
|
| for (size_t j = 0; j < results.size(); ++j) { |
| if (j <= i) { |
| BOOST_CHECK_EQUAL(results[j], 1); |
| } else { |
| BOOST_CHECK_EQUAL(results[j], 0); |
| } |
| } |
| } |
|
|
| pool.Wait(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestThreadPoolGetThreadIndex) { |
| ThreadPool pool(4); |
|
|
| std::vector<int> results(100, -1); |
| std::function<void(int)> Func = [&](const int num) { |
| results[num] = pool.GetThreadIndex(); |
| }; |
|
|
| for (size_t i = 0; i < results.size(); ++i) { |
| pool.AddTask(Func, i); |
| } |
|
|
| pool.Wait(); |
|
|
| for (const auto result : results) { |
| BOOST_CHECK_GE(result, 0); |
| BOOST_CHECK_LE(result, 3); |
| } |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueSingleProducerSingleConsumer) { |
| JobQueue<int> job_queue; |
|
|
| |
| |
|
|
| std::thread producer_thread([&job_queue]() { |
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread consumer_thread([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 10); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 10); |
| } |
| }); |
|
|
| producer_thread.join(); |
| consumer_thread.join(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueSingleProducerSingleConsumerMaxNumJobs) { |
| JobQueue<int> job_queue(2); |
|
|
| |
| |
|
|
| std::thread producer_thread([&job_queue]() { |
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread consumer_thread([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 2); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 10); |
| } |
| }); |
|
|
| producer_thread.join(); |
| consumer_thread.join(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueMultipleProducerSingleConsumer) { |
| JobQueue<int> job_queue(1); |
|
|
| |
| |
|
|
| std::thread producer_thread1([&job_queue]() { |
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread producer_thread2([&job_queue]() { |
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread consumer_thread([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 1); |
| for (int i = 0; i < 20; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 10); |
| } |
| }); |
|
|
| producer_thread1.join(); |
| producer_thread2.join(); |
| consumer_thread.join(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueSingleProducerMultipleConsumer) { |
| JobQueue<int> job_queue(1); |
|
|
| |
| |
|
|
| std::thread producer_thread([&job_queue]() { |
| for (int i = 0; i < 20; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread consumer_thread1([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 1); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 20); |
| } |
| }); |
|
|
| std::thread consumer_thread2([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 1); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 20); |
| } |
| }); |
|
|
| producer_thread.join(); |
| consumer_thread1.join(); |
| consumer_thread2.join(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueMultipleProducerMultipleConsumer) { |
| JobQueue<int> job_queue(1); |
|
|
| |
| |
|
|
| std::thread producer_thread1([&job_queue]() { |
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread producer_thread2([&job_queue]() { |
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
| }); |
|
|
| std::thread consumer_thread1([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 1); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 10); |
| } |
| }); |
|
|
| std::thread consumer_thread2([&job_queue]() { |
| CHECK_LE(job_queue.Size(), 1); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_LT(job.Data(), 10); |
| } |
| }); |
|
|
| producer_thread1.join(); |
| producer_thread2.join(); |
| consumer_thread1.join(); |
| consumer_thread2.join(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueWait) { |
| JobQueue<int> job_queue; |
|
|
| |
| |
|
|
| for (int i = 0; i < 10; ++i) { |
| CHECK(job_queue.Push(i)); |
| } |
|
|
| std::thread consumer_thread([&job_queue]() { |
| CHECK_EQ(job_queue.Size(), 10); |
| for (int i = 0; i < 10; ++i) { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_EQ(job.Data(), i); |
| } |
| }); |
|
|
| job_queue.Wait(); |
|
|
| BOOST_CHECK_EQUAL(job_queue.Size(), 0); |
| BOOST_CHECK(job_queue.Push(0)); |
| BOOST_CHECK(job_queue.Pop().IsValid()); |
|
|
| consumer_thread.join(); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueStopProducer) { |
| JobQueue<int> job_queue(1); |
|
|
| |
| |
|
|
| Barrier stopBarrier; |
| std::thread producer_thread([&job_queue, &stopBarrier]() { |
| CHECK(job_queue.Push(0)); |
| stopBarrier.Wait(); |
| CHECK(!job_queue.Push(0)); |
| }); |
|
|
| stopBarrier.Wait(); |
| BOOST_CHECK_EQUAL(job_queue.Size(), 1); |
|
|
| job_queue.Stop(); |
| producer_thread.join(); |
|
|
| BOOST_CHECK(!job_queue.Push(0)); |
| BOOST_CHECK(!job_queue.Pop().IsValid()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueStopConsumer) { |
| JobQueue<int> job_queue(1); |
|
|
| |
| |
|
|
| BOOST_CHECK(job_queue.Push(0)); |
|
|
| Barrier popBarrier; |
| std::thread consumer_thread([&job_queue, &popBarrier]() { |
| const auto job = job_queue.Pop(); |
| CHECK(job.IsValid()); |
| CHECK_EQ(job.Data(), 0); |
| popBarrier.Wait(); |
| CHECK(!job_queue.Pop().IsValid()); |
| }); |
|
|
| popBarrier.Wait(); |
| BOOST_CHECK_EQUAL(job_queue.Size(), 0); |
|
|
| job_queue.Stop(); |
| consumer_thread.join(); |
|
|
| BOOST_CHECK(!job_queue.Push(0)); |
| BOOST_CHECK(!job_queue.Pop().IsValid()); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestJobQueueClear) { |
| JobQueue<int> job_queue(1); |
|
|
| BOOST_CHECK(job_queue.Push(0)); |
| BOOST_CHECK_EQUAL(job_queue.Size(), 1); |
|
|
| job_queue.Clear(); |
| BOOST_CHECK_EQUAL(job_queue.Size(), 0); |
| } |
|
|
| BOOST_AUTO_TEST_CASE(TestGetEffectiveNumThreads) { |
| BOOST_CHECK_GT(GetEffectiveNumThreads(-2), 0); |
| BOOST_CHECK_GT(GetEffectiveNumThreads(-1), 0); |
| BOOST_CHECK_GT(GetEffectiveNumThreads(0), 0); |
| BOOST_CHECK_EQUAL(GetEffectiveNumThreads(1), 1); |
| BOOST_CHECK_EQUAL(GetEffectiveNumThreads(2), 2); |
| BOOST_CHECK_EQUAL(GetEffectiveNumThreads(3), 3); |
| } |
|
|