From ed9c0d2c636cc25a6f1a55f4c4d54eb102cd4e5e Mon Sep 17 00:00:00 2001 From: khizmax Date: Wed, 20 Jan 2016 19:25:55 +0300 Subject: [PATCH] Test thread initial version --- projects/Win/vc14/cds.sln | 1 + test/include/cds_test/thread.h | 234 +++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 test/include/cds_test/thread.h diff --git a/projects/Win/vc14/cds.sln b/projects/Win/vc14/cds.sln index 9674e163..f827d9ab 100644 --- a/projects/Win/vc14/cds.sln +++ b/projects/Win/vc14/cds.sln @@ -192,6 +192,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cds_test", "cds_test", "{3A510E45-180B-4ADC-AFCD-D75774B68580}" ProjectSection(SolutionItems) = preProject ..\..\..\test\include\cds_test\fixture.h = ..\..\..\test\include\cds_test\fixture.h + ..\..\..\test\include\cds_test\thread.h = ..\..\..\test\include\cds_test\thread.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-deque", "gtest-deque.vcxproj", "{20A9F084-D01F-47E5-B775-4F4B48504FCC}" diff --git a/test/include/cds_test/thread.h b/test/include/cds_test/thread.h new file mode 100644 index 00000000..4f813bd5 --- /dev/null +++ b/test/include/cds_test/thread.h @@ -0,0 +1,234 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSTEST_THREAD_H +#define CDSTEST_THREAD_H + +#include +#include +#include +#include +#include +#include + +namespace cds_test { + + // Forwards + class thread; + class thread_pool; + + // Test thread + class thread + { + void run(); + + protected: // thread_pool interface + thread( thread const& sample ); + + virtual ~thread() + {} + + void join() { m_impl.join(); } + + protected: + virtual thread * clone() = 0; + virtual void test() = 0; + + virtual void SetUp() + {} + virtual void TearDown() + {} + + public: + explicit thread( thread_pool& master, int type = 0 ); + + thread_pool& pool() { return m_pool; } + int type() const { return m_type; } + size_t id() const { return m_id; } + + private: + friend class thread_pool; + + thread_pool& m_pool; + int m_type; + size_t m_id; + std::thread m_impl; + }; + + // Pool of test threads + class thread_pool + { + public: + explicit thread_pool( ::testing::Test& fixture ) + : m_fixture( fixture ) + , m_bRunning( false ) + , m_bStopped( false ) + , m_doneCount( 0 ) + {} + + ~thread_pool() + { + for ( auto t : m_threads ) + delete t; + } + + void add( thread& what ) + { + m_threads.push_back( &what ); + what.run(); + } + + void add( thread& what, size_t count ) + { + add( what ); + for ( size_t i = 1; i < count; ++i ) { + thread * p = what.clone(); + add( *p ); + } + } + + std::chrono::milliseconds run() + { + m_bStopped = false; + m_doneCount = 0; + + auto time_start = std::chrono::steady_clock::now(); + + m_bRunning = true; + m_cvStart.notify_all(); + + { + scoped_lock l( m_cvMutex ); + while ( m_doneCount != m_threads.size() ) + m_cvDone.wait( l ); + m_bStopped = true; + } + auto time_end = std::chrono::steady_clock::now(); + + m_cvStop.notify_all(); + + for ( auto t : m_threads ) + t->join(); + + return m_testDuration = time_end - time_start; + } + + size_t size() const { return m_threads.size(); } + thread& get( size_t idx ) const { return *m_threads.at( idx ); } + + template + Fixture& fixture() + { + return static_cast(m_fixture); + } + + std::chrono::milliseconds duration() const { return m_testDuration; } + + protected: // thread interface + size_t get_next_id() + { + return m_threads.size(); + } + + void ready_to_start( thread& /*who*/ ) + { + // Called from test thread + + // Wait for all thread created + scoped_lock l( m_cvMutex ); + while ( !m_bRunning ) + m_cvStart.wait( l ); + } + + void thread_done( thread& /*who*/ ) + { + // Called from test thread + + { + scoped_lock l( m_cvMutex ); + ++m_doneCount; + } + + // Tell pool that the thread is done + m_cvDone.notify_all(); + + // Wait for all thread done + { + scoped_lock l( m_cvMutex ); + while ( !m_bStopped ) + m_cvStop.wait( l ); + } + } + + private: + friend class thread; + + ::testing::Test& m_fixture; + std::vector m_threads; + + typedef std::unique_lock scoped_lock; + std::mutex m_cvMutex; + std::condition_variable m_cvStart; + std::condition_variable m_cvStop; + std::condition_variable m_cvDone; + + volatile bool m_bRunning; + volatile bool m_bStopped; + volatile size_t m_doneCount; + + std::chrono::milliseconds m_testDuration; + }; + + inline thread::thread( thread_pool& master, int type = 0 ) + : m_pool( master ) + , m_type( type ) + , m_id( master.get_next_id()) + , m_impl( &run, this ) + {} + + inline thread::thread( thread const& sample ) + : m_pool( sample.m_pool ) + , m_type( sample.m_type ) + , m_id( m_pool.get_next_id() ) + , m_impl( &run, this ) + {} + + inline void thread::run() + { + SetUp(); + m_pool.ready_to_start( *this ); + test(); + m_pool.thread_done( *this ); + TearDown(); + } + +} // namespace cds_test + +#endif // CDSTEST_THREAD_H -- 2.34.1