diff --git a/lib/main/thread/piblockingdequeue.h b/lib/main/thread/piblockingdequeue.h index 27e23572..2ca96bbd 100644 --- a/lib/main/thread/piblockingdequeue.h +++ b/lib/main/thread/piblockingdequeue.h @@ -20,6 +20,7 @@ #ifndef PIBLOCKINGDEQUEUE_H #define PIBLOCKINGDEQUEUE_H +#include #include "pideque.h" #include "piconditionvar.h" @@ -28,8 +29,9 @@ * wait for space to become available in the queue when storing an element. */ template -class PIBlockingDequeue: private PIDeque { +class PIBlockingDequeue { public: + typedef typename std::deque QueueType; /** * @brief Constructor @@ -42,21 +44,21 @@ public: /** * @brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue. */ - explicit inline PIBlockingDequeue(const PIDeque& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { + explicit inline PIBlockingDequeue(const QueueType& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { mutex.lock(); max_size = SIZE_MAX; - PIDeque::append(other); + data_queue = QueueType(other); mutex.unlock(); } /** * @brief Thread-safe copy constructor. Initialize queue with copy of other queue elements. */ - inline PIBlockingDequeue(PIBlockingDequeue & other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { + inline PIBlockingDequeue(PIBlockingDequeue& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { other.mutex.lock(); mutex.lock(); max_size = other.max_size; - PIDeque::append(static_cast&>(other)); + data_queue = QueueType(other.data_queue); mutex.unlock(); other.mutex.unlock(); } @@ -71,10 +73,10 @@ public: * * @param v the element to add */ - void put(const T & v) { + void put(T && v) { mutex.lock(); - cond_var_rem->wait(mutex, [&]() { return PIDeque::size() < max_size; }); - PIDeque::push_back(v); + cond_var_rem->wait(mutex, [&]() { return data_queue.size() < max_size; }); + data_queue.push_back(std::forward(v)); mutex.unlock(); cond_var_add->notifyOne(); } @@ -86,13 +88,13 @@ public: * @param v the element to add * @return true if the element was added to this queue, else false */ - bool offer(const T & v) { + bool offer(T && v) { mutex.lock(); - if (PIDeque::size() >= max_size) { + if (data_queue.size() >= max_size) { mutex.unlock(); return false; } - PIDeque::push_back(v); + data_queue.push_back(std::forward(v)); mutex.unlock(); cond_var_add->notifyOne(); return true; @@ -106,10 +108,10 @@ public: * @param timeoutMs how long to wait before giving up, in milliseconds * @return true if successful, or false if the specified waiting time elapses before space is available */ - bool offer(const T & v, int timeoutMs) { + bool offer(T && v, int timeoutMs) { mutex.lock(); - bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque::size() < max_size; } ); - if (isOk) PIDeque::push_back(v); + bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return data_queue.size() < max_size; } ); + if (isOk) data_queue.push_back(std::forward(v)); mutex.unlock(); if (isOk) cond_var_add->notifyOne(); return isOk; @@ -121,10 +123,10 @@ public: * @return the head of this queue */ T take() { - T t; mutex.lock(); - cond_var_add->wait(mutex, [&]() { return !PIDeque::isEmpty(); }); - t = T(PIDeque::take_front()); + cond_var_add->wait(mutex, [&]() { return !data_queue.empty(); }); + T t = std::move(data_queue.front()); + data_queue.pop_front(); mutex.unlock(); cond_var_rem->notifyOne(); return t; @@ -140,11 +142,16 @@ public: * return value is retrieved value * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available */ - T poll(int timeoutMs, const T & defaultVal = T(), bool * isOk = nullptr) { - T t; + T poll(int timeoutMs, T && defaultVal = T(), bool * isOk = nullptr) { mutex.lock(); - bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque::isEmpty(); }); - t = isNotEmpty ? T(PIDeque::take_front()) : defaultVal; + bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !data_queue.empty(); }); + T t; + if (isNotEmpty) { + t = std::move(data_queue.front()); + data_queue.pop_front(); + } else { + t = std::move(defaultVal); + } mutex.unlock(); if (isNotEmpty) cond_var_rem->notifyOne(); if (isOk) *isOk = isNotEmpty; @@ -160,11 +167,16 @@ public: * return value is retrieved value * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available */ - T poll(const T & defaultVal = T(), bool * isOk = nullptr) { + T poll(T && defaultVal = T(), bool * isOk = nullptr) { T t; mutex.lock(); - bool isNotEmpty = !PIDeque::isEmpty(); - t = isNotEmpty ? PIDeque::take_front() : defaultVal; + bool isNotEmpty = !data_queue.empty(); + if (isNotEmpty) { + t = std::move(data_queue.front()); + data_queue.pop_front(); + } else { + t = std::move(defaultVal); + } mutex.unlock(); if (isNotEmpty) cond_var_rem->notifyOne(); if (isOk) *isOk = isNotEmpty; @@ -193,7 +205,7 @@ public: */ size_t remainingCapacity() { mutex.lock(); - size_t c = max_size - PIDeque::size(); + size_t c = max_size - data_queue.size(); mutex.unlock(); return c; } @@ -203,7 +215,7 @@ public: */ size_t size() { mutex.lock(); - size_t s = PIDeque::size(); + size_t s = data_queue.size(); mutex.unlock(); return s; } @@ -211,10 +223,13 @@ public: /** * @brief Removes all available elements from this queue and adds them to other given queue. */ - size_t drainTo(PIDeque& other, size_t maxCount = SIZE_MAX) { + size_t drainTo(QueueType& other, size_t maxCount = SIZE_MAX) { mutex.lock(); - size_t count = ((maxCount > PIDeque::size()) ? PIDeque::size() : maxCount); - for (size_t i = 0; i < count; ++i) other.push_back(PIDeque::take_front()); + size_t count = ((maxCount > data_queue.size()) ? data_queue.size() : maxCount); + for (size_t i = 0; i < count; ++i) { + other.push_back(std::move(data_queue.front())); + data_queue.pop_front(); + } mutex.unlock(); return count; } @@ -225,10 +240,13 @@ public: size_t drainTo(PIBlockingDequeue& other, size_t maxCount = SIZE_MAX) { mutex.lock(); other.mutex.lock(); - size_t count = maxCount > PIDeque::size() ? PIDeque::size() : maxCount; - size_t otherRemainingCapacity = other.max_size - static_cast >(other).size(); + size_t count = maxCount > data_queue.size() ? data_queue.size() : maxCount; + size_t otherRemainingCapacity = other.max_size - data_queue.size(); if (count > otherRemainingCapacity) count = otherRemainingCapacity; - for (size_t i = 0; i < count; ++i) other.push_back(PIDeque::take_front()); + for (size_t i = 0; i < count; ++i) { + other.data_queue.push_back(std::move(data_queue.front())); + data_queue.pop_front(); + } other.mutex.unlock(); mutex.unlock(); return count; @@ -237,6 +255,7 @@ public: private: PIMutex mutex; PIConditionVariable * cond_var_add, * cond_var_rem; + QueueType data_queue; size_t max_size; }; diff --git a/lib/main/thread/piexecutor.h b/lib/main/thread/piexecutor.h index 1048173a..3fb31f37 100644 --- a/lib/main/thread/piexecutor.h +++ b/lib/main/thread/piexecutor.h @@ -22,8 +22,47 @@ #include "piblockingdequeue.h" #include +#include -template +/** + * @brief Wrapper for custom invoke operator available function types. + * @note Source from: "Энтони Уильямс, Параллельное программирование на С++ в действии. Практика разработки многопоточных + * программ. Пер. с англ. Слинкин А. А. - M.: ДМК Пресс, 2012 - 672c.: ил." (page 387) + */ +class FunctionWrapper { + struct ImplBase { + virtual void call() = 0; + virtual ~ImplBase() = default; + }; + + std::unique_ptr impl; + + template + struct ImplType: ImplBase { + F f; + explicit ImplType(F&& f): f(std::forward(f)) {} + void call() final { f(); } + }; +public: + template::value> > + explicit FunctionWrapper(F&& f): impl(new ImplType(std::forward(f))) {} + + void operator()() { impl->call(); } + + explicit operator bool() const noexcept { return static_cast(impl); } + + FunctionWrapper() = default; + FunctionWrapper(FunctionWrapper&& other) noexcept : impl(std::move(other.impl)) {} + FunctionWrapper& operator=(FunctionWrapper&& other) noexcept { + impl = std::move(other.impl); + return *this; + } + + FunctionWrapper(const FunctionWrapper& other) = delete; + FunctionWrapper& operator=(const FunctionWrapper&) = delete; +}; + +template class Dequeue_> class PIThreadPoolExecutorTemplate { public: NO_COPY_CLASS(PIThreadPoolExecutorTemplate) @@ -34,8 +73,27 @@ public: while (threadPool.size() > 0) delete threadPool.take_back(); } - void execute(const std::function & runnable) { - if (!isShutdown_) taskQueue.offer(runnable); + template + std::future::type> submit(FunctionType&& callable) { + typedef typename std::result_of::type ResultType; + + if (!isShutdown_) { + std::packaged_task callable_task(std::forward(callable)); + auto future = callable_task.get_future(); + FunctionWrapper functionWrapper(callable_task); + taskQueue.offer(std::move(functionWrapper)); + return future; + } else { + return std::future(); + } + } + + template + void execute(FunctionType&& runnable) { + if (!isShutdown_) { + FunctionWrapper function_wrapper(std::forward(runnable)); + taskQueue.offer(std::move(function_wrapper)); + } } void shutdown() { @@ -63,15 +121,15 @@ public: protected: std::atomic_bool isShutdown_; - Dequeue_ taskQueue; + Dequeue_ taskQueue; PIVector threadPool; template - PIThreadPoolExecutorTemplate(size_t corePoolSize, Function onBeforeStart) : isShutdown_(false) { - makePool(corePoolSize, onBeforeStart); + PIThreadPoolExecutorTemplate(size_t corePoolSize, Function&& onBeforeStart) : isShutdown_(false) { + makePool(corePoolSize, std::forward(onBeforeStart)); } - void makePool(size_t corePoolSize, std::function onBeforeStart = [](Thread_*){}) { + void makePool(size_t corePoolSize, std::function&& onBeforeStart = [](Thread_*){}) { for (size_t i = 0; i < corePoolSize; ++i) { auto* thread = new Thread_([&, i](){ auto runnable = taskQueue.poll(100); @@ -87,7 +145,7 @@ protected: } }; -typedef PIThreadPoolExecutorTemplate > > PIThreadPoolExecutor; +typedef PIThreadPoolExecutorTemplate PIThreadPoolExecutor; #ifdef DOXYGEN /** diff --git a/tests/concurrent/BlockingDequeueUnitTest.cpp b/tests/concurrent/BlockingDequeueUnitTest.cpp index fae9f3ff..235f4e54 100644 --- a/tests/concurrent/BlockingDequeueUnitTest.cpp +++ b/tests/concurrent/BlockingDequeueUnitTest.cpp @@ -1,4 +1,5 @@ #include "gtest/gtest.h" +#include "testutil.h" #include "piblockingdequeue.h" class MockConditionVar: public PIConditionVariable { @@ -236,10 +237,10 @@ TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) { TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) { size_t capacity = 10; - PIDeque refDeque; + PIBlockingDequeue::QueueType refDeque; for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); PIBlockingDequeue blockingDequeue(refDeque); - PIDeque deque; + PIBlockingDequeue::QueueType deque; blockingDequeue.drainTo(deque); ASSERT_EQ(blockingDequeue.size(), 0); ASSERT_TRUE(deque == refDeque); @@ -247,18 +248,18 @@ TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) { TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_size_when_all_moved) { size_t capacity = 10; - PIDeque refDeque; + PIBlockingDequeue::QueueType refDeque; for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); PIBlockingDequeue blockingDequeue(refDeque); - PIDeque deque; + PIBlockingDequeue::QueueType deque; ASSERT_EQ(blockingDequeue.drainTo(deque), refDeque.size()); } TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_maxCount) { size_t capacity = 10; - PIDeque refDeque; + PIBlockingDequeue::QueueType refDeque; for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); PIBlockingDequeue blockingDequeue(refDeque); - PIDeque deque; + PIBlockingDequeue::QueueType deque; ASSERT_EQ(blockingDequeue.drainTo(deque, refDeque.size() - 1), refDeque.size() - 1); } diff --git a/tests/concurrent/ConditionVariableIntegrationTest.cpp b/tests/concurrent/ConditionVariableIntegrationTest.cpp index b8d82a92..dc5d7bf2 100644 --- a/tests/concurrent/ConditionVariableIntegrationTest.cpp +++ b/tests/concurrent/ConditionVariableIntegrationTest.cpp @@ -3,7 +3,7 @@ #include "pithread.h" #include "testutil.h" -class ConditionVariable : public ::testing::Test, public TestUtil { +class ConditionVariableIntegrationTest : public ::testing::Test, public TestUtil { public: PIMutex m; PIConditionVariable* variable; @@ -19,30 +19,30 @@ protected: } }; -TEST_F(ConditionVariable, wait_is_block) { +TEST_F(ConditionVariableIntegrationTest, wait_is_block) { createThread(); ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); } -TEST_F(ConditionVariable, wait_is_block_when_notifyOne_before_wait) { +TEST_F(ConditionVariableIntegrationTest, wait_is_block_when_notifyOne_before_wait) { variable->notifyOne(); createThread(); ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); } -TEST_F(ConditionVariable, wait_is_block_when_notifyAll_before_wait) { +TEST_F(ConditionVariableIntegrationTest, wait_is_block_when_notifyAll_before_wait) { variable->notifyAll(); createThread(); ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); } -TEST_F(ConditionVariable, wait_is_unblock_when_notifyOne_after_wait) { +TEST_F(ConditionVariableIntegrationTest, wait_is_unblock_when_notifyOne_after_wait) { createThread(); variable->notifyOne(); ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); } -TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) { +TEST_F(ConditionVariableIntegrationTest, wait_is_unblock_when_notifyAll_after_wait) { PIVector threads; for (int i = 0; i < THREAD_COUNT; ++i) { @@ -61,7 +61,7 @@ TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) { piForeach(PIThread* thread, threads) delete thread; } -TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) { +TEST_F(ConditionVariableIntegrationTest, wait_is_one_unblock_when_notifyOne) { PIVector threads; for (int i = 0; i < THREAD_COUNT; ++i) { @@ -77,7 +77,7 @@ TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) { ASSERT_EQ(runningThreadCount, THREAD_COUNT - 1); } -TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) { +TEST_F(ConditionVariableIntegrationTest, wait_is_protected_unblock_when_notifyOne) { createThread([&](){ m.lock(); variable->wait(m); @@ -89,7 +89,7 @@ TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) { ASSERT_FALSE(m.tryLock()); } -TEST_F(ConditionVariable, wait_condition_is_block) { +TEST_F(ConditionVariableIntegrationTest, wait_condition_is_block) { createThread([&](){ m.lock(); variable->wait(m, [](){ return false; }); @@ -98,7 +98,7 @@ TEST_F(ConditionVariable, wait_condition_is_block) { ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); } -TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) { +TEST_F(ConditionVariableIntegrationTest, wait_condition_is_check_condition_before_block) { bool isConditionChecked = false; createThread([&](){ m.lock(); @@ -113,7 +113,7 @@ TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) { m.unlock(); } -TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) { +TEST_F(ConditionVariableIntegrationTest, wait_condition_is_check_condition_when_notifyOne) { bool isConditionChecked; createThread([&](){ m.lock(); @@ -133,7 +133,7 @@ TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) { m.unlock(); } -TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne) { +TEST_F(ConditionVariableIntegrationTest, wait_condition_is_unblock_when_condition_and_notifyOne) { bool condition = false; createThread([&](){ m.lock(); @@ -147,7 +147,7 @@ TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); } -TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) { +TEST_F(ConditionVariableIntegrationTest, DISABLED_waitFor_is_block_before_timeout) { createThread([&](){ PITimeMeasurer measurer; m.lock(); @@ -159,7 +159,7 @@ TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) { EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS * 3)); } -TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) { +TEST_F(ConditionVariableIntegrationTest, waitFor_is_unblock_when_timeout) { std::atomic_bool isUnblock(false); createThread([&](){ m.lock(); @@ -172,7 +172,7 @@ TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) { ASSERT_TRUE(isUnblock); } -TEST_F(ConditionVariable, waitFor_is_false_when_timeout) { +TEST_F(ConditionVariableIntegrationTest, waitFor_is_false_when_timeout) { bool waitRet = true; createThread([&](){ m.lock(); @@ -183,7 +183,7 @@ TEST_F(ConditionVariable, waitFor_is_false_when_timeout) { ASSERT_FALSE(waitRet); } -TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) { +TEST_F(ConditionVariableIntegrationTest, waitFor_is_unblock_when_condition_and_notifyOne) { bool condition = false; createThread([&](){ m.lock(); diff --git a/tests/concurrent/ExecutorIntegrationTest.cpp b/tests/concurrent/ExecutorIntegrationTest.cpp index 326eca91..eeb6400b 100644 --- a/tests/concurrent/ExecutorIntegrationTest.cpp +++ b/tests/concurrent/ExecutorIntegrationTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" -#include "piexecutor.h" -#include "pimutex.h" #include "testutil.h" +#include "pimutex.h" +#include "piexecutor.h" TEST(ExcutorIntegrationTest, execute_is_runnable_invoke) { PIMutex m; diff --git a/tests/concurrent/ExecutorUnitTest.cpp b/tests/concurrent/ExecutorUnitTest.cpp index a9261297..e4c1eed3 100644 --- a/tests/concurrent/ExecutorUnitTest.cpp +++ b/tests/concurrent/ExecutorUnitTest.cpp @@ -1,13 +1,14 @@ #include "gtest/gtest.h" #include "gmock/gmock.h" -#include "piexecutor.h" #include "testutil.h" +#include "piexecutor.h" using ::testing::_; using ::testing::SetArgReferee; using ::testing::DoAll; using ::testing::DeleteArg; using ::testing::Return; +using ::testing::ByMove; using ::testing::AtLeast; using ::testing::ByRef; using ::testing::Eq; @@ -27,9 +28,9 @@ namespace std { class MockThread { public: - std::function runnnable; + VoidFunc runnnable; - MockThread(std::function runnnable) : runnnable(runnnable) { } + MockThread(VoidFunc runnnable) : runnnable(runnnable) { } MOCK_METHOD0(start, bool()); MOCK_METHOD0(stop, void()); @@ -37,11 +38,12 @@ public: MOCK_METHOD1(waitForFinish, bool(int timeout_msecs)); }; -class MockDeque : public PIBlockingDequeue { +template +class MockDeque : public PIBlockingDequeue { public: - MOCK_METHOD1(offer, bool(const VoidFunc&)); - MOCK_METHOD0(take, VoidFunc()); - MOCK_METHOD1(poll, VoidFunc(int)); + MOCK_METHOD1(offer, bool(const FunctionWrapper&)); + MOCK_METHOD0(take, FunctionWrapper()); + MOCK_METHOD1(poll, FunctionWrapper(int)); MOCK_METHOD0(capacity, size_t()); MOCK_METHOD0(remainingCapacity, size_t()); }; @@ -57,7 +59,7 @@ public: PIVector*>* getThreadPool() { return &threadPool; } bool isShutdown() { return isShutdown_; } - MockDeque* getTaskQueue() { return &taskQueue; } + MockDeque* getTaskQueue() { return &taskQueue; } }; TEST(ExecutorUnitTest, is_corePool_created) { @@ -73,10 +75,30 @@ TEST(ExecutorUnitTest, is_corePool_started) { EXPECT_EQ(THREAD_COUNT, executor.getThreadPool()->size()); } +TEST(ExecutorUnitTest, submit_is_added_to_taskQueue) { + VoidFunc voidFunc = [](){}; + PIThreadPoolExecutorMoc executor(THREAD_COUNT); + // TODO add check of offered + EXPECT_CALL(*executor.getTaskQueue(), offer) + .WillOnce(Return(true)); + executor.submit(voidFunc); +} + +TEST(ExecutorUnitTest, submit_is_return_valid_future) { + VoidFunc voidFunc = [](){}; + PIThreadPoolExecutorMoc executor(THREAD_COUNT); + // TODO add check of offered + EXPECT_CALL(*executor.getTaskQueue(), offer) + .WillOnce(Return(true)); + auto future = executor.submit(voidFunc); + EXPECT_TRUE(future.valid()); +} + TEST(ExecutorUnitTest, execute_is_added_to_taskQueue) { VoidFunc voidFunc = [](){}; PIThreadPoolExecutorMoc executor(THREAD_COUNT); - EXPECT_CALL(*executor.getTaskQueue(), offer(Eq(voidFunc))) + // TODO add check of offered + EXPECT_CALL(*executor.getTaskQueue(), offer) .WillOnce(Return(true)); executor.execute(voidFunc); } @@ -85,8 +107,10 @@ TEST(ExecutorUnitTest, is_corePool_execute_queue_elements) { bool is_executed = false; PIThreadPoolExecutorMoc executor(1); EXPECT_EQ(executor.getThreadPool()->size(), 1); - EXPECT_CALL(*executor.getTaskQueue(), poll(Ge(0))) - .WillOnce(Return([&](){ is_executed = true; })); + EXPECT_CALL(*executor.getTaskQueue(), poll(Ge(0))) + .WillOnce([&is_executed](int){ + return FunctionWrapper([&is_executed](){ is_executed = true; }); + }); executor.getThreadPool()->at(0)->runnnable(); ASSERT_TRUE(is_executed); } @@ -102,7 +126,7 @@ TEST(ExecutorUnitTest, shutdown_is_stop_threads) { testing::Mock::AllowLeak(executor->getTaskQueue()); EXPECT_CALL(*executor->getTaskQueue(), poll(Ge(0))) - .WillRepeatedly(Return(std::function())); + .WillRepeatedly([](int){ return FunctionWrapper(); }); executor->shutdown(); executor->getThreadPool()->forEach([](MockThread* thread){ thread->runnnable(); }); } diff --git a/tests/concurrent/MutexIntegrationTest.cpp b/tests/concurrent/MutexIntegrationTest.cpp index 882050c4..127432e1 100644 --- a/tests/concurrent/MutexIntegrationTest.cpp +++ b/tests/concurrent/MutexIntegrationTest.cpp @@ -3,12 +3,12 @@ #include "pithread.h" #include "testutil.h" -class Mutex : public ::testing::Test, public TestUtil { +class MutexIntegartionTest : public ::testing::Test, public TestUtil { public: PIMutex* m = new PIMutex(); }; -TEST_F(Mutex, lock_is_protect) { +TEST_F(MutexIntegartionTest, lock_is_protect) { m->lock(); bool* isProtect = new bool(true); @@ -20,7 +20,7 @@ TEST_F(Mutex, lock_is_protect) { ASSERT_TRUE(*isProtect); } -TEST_F(Mutex, unlock_is_release) { +TEST_F(MutexIntegartionTest, unlock_is_release) { m->lock(); bool* isReleased = new bool(false); m->unlock(); @@ -33,7 +33,7 @@ TEST_F(Mutex, unlock_is_release) { ASSERT_TRUE(*isReleased); } -TEST_F(Mutex, tryLock_is_false_when_locked) { +TEST_F(MutexIntegartionTest, tryLock_is_false_when_locked) { createThread([&](){ m->lock(); piMSleep(WAIT_THREAD_TIME_MS); @@ -41,11 +41,11 @@ TEST_F(Mutex, tryLock_is_false_when_locked) { ASSERT_FALSE(m->tryLock()); } -TEST_F(Mutex, tryLock_is_true_when_unlocked) { +TEST_F(MutexIntegartionTest, tryLock_is_true_when_unlocked) { ASSERT_TRUE(m->tryLock()); } -TEST_F(Mutex, tryLock_is_recursive_lock_enable) { +TEST_F(MutexIntegartionTest, tryLock_is_recursive_lock_enable) { m->lock(); ASSERT_TRUE(m->tryLock()); } diff --git a/tests/concurrent/testutil.h b/tests/concurrent/testutil.h index 6bb4fa2a..1a692ad2 100644 --- a/tests/concurrent/testutil.h +++ b/tests/concurrent/testutil.h @@ -4,11 +4,19 @@ #include "pithread.h" #include +template +void print_type_info() { + std::cout << typeid(T).name() << " is a " + << (std::is_const::type>::value ? "const " : "") + << (std::is_lvalue_reference::value ? "lvalue" : "rvalue") + << " reference" << std::endl; +} + /** * Minimum wait thread start, switch context or another interthread communication action time. Increase it if tests * write "Start thread timeout reach!" message. You can reduce it if you want increase test performance. */ -const int WAIT_THREAD_TIME_MS = 10; +const int WAIT_THREAD_TIME_MS = 30; const int THREAD_COUNT = 2;