Ответ 1
Вы думаете, что пять минут - это долго ждать завершения тестов! Попробуйте несколько часов. У меня была мотивация для следующего.
Использование потоков увеличения, потоки CppUnit довольно просты. У CppUnit уже есть некоторые перехватчики для синхронизации, поэтому следующее должно сделать это потокобезопасным:
class Mutex : public CPPUNIT_NS::SynchronizedObject::SynchronizationObject
{
public:
void lock() { this->mutex->lock(); }
void unlock() { this->mutex->unlock(); }
private:
boost::mutex mutex;
};
С помощью этого вы можете изменить свой тестовый бегун, чтобы сделать поток TestResult
безопасным. Просто напишите что-нибудь вроде CPPUNIT_NS::TestResult testResult(new Mutex);
. Теперь вот набор тестовых пакетов:
class TestSuiteThreaded : public CPPUNIT_NS::TestSuite
{
public:
TestSuiteThreaded(std::string name = "", int nThreads = 0)
: TestSuite(name)
, nThreads(nThreads ? nThreads : boost::thread::hardware_concurrency())
{
}
void doRunChildTests(CPPUNIT_NS::TestResult *controller)
{
ThreadPool pool(this->nThreads);
for (int i=0; i < getChildTestCount(); ++i)
{
pool.add(
boost::bind(threadFunction, getChildTestAt(i)
, controller));
}
}
private:
static void threadFunction(
CPPUNIT_NS::Test *test,
CPPUNIT_NS::TestResult *controller)
{
test->run(controller);
}
const int nThreads;
};
Вам может понадобиться макрос для удобства использования набора для потоковой проверки. Вы должны иметь возможность использовать пакет TestSuiteThreaded
либо как набор верхнего уровня, либо набор, содержащий несколько методов одного и того же текстового инструментария. Здесь, как вы делаете последнее, поставьте это вместо CPPUNIT_TEST_SUITE_END
. Некоторые из них вставляются из CppUnit, поэтому, пожалуйста, соблюдайте лицензию:
#define CPPUNIT_TEST_SUITE_END_THREADED(n) \
} \
static CPPUNIT_NS::TestSuite *suite() \
{ \
const CPPUNIT_NS::TestNamer &namer = getTestNamer__(); \
std::auto_ptr<CPPUNIT_NS::TestSuite> suite( \
new CPPUNIT_NS::TestSuiteThreaded( namer.getFixtureName(), n)); \
CPPUNIT_NS::ConcretTestFixtureFactory<TestFixtureType> factory; \
CPPUNIT_NS::TestSuiteBuilderContextBase context( *suite.get(), \
namer, \
factory ); \
TestFixtureType::addTestsToSuite( context ); \
return suite.release(); \
} \
private: /* dummy typedef so that the macro can still end with ';'*/ \
typedef int CppUnitDummyTypedefForSemiColonEnding__
Теперь существует небольшое значение a ThreadPool
. Я пробовал использовать различные общедоступные, без успеха. У моей компании есть одна, но я не могу ее опубликовать здесь. Итак, сворачивайте свои собственные - пулы потоков довольно легко и забавно сделать с помощью Boost. Вот интерфейс, ожидаемый TestSuiteThreaded
:
class ThreadPool
{
public:
// Create thread pool, launching n worker threads
ThreadPool(unsigned n);
// Join all worker threads and clean up
~ThreadPool();
// You can have add() do one of two things. Both will work:
// Either: push a new task to the back of the threadpool work queue
// Or: block until a worker is free then assign task to that thread
void add(boost::function0<void> task);
};
Я оставляю это как упражнение для читателя. Получайте удовольствие!