与其为每个任务生成一个新线程,不如只形成几个工作线程,然后使用std:packaged_task
andstd::future
来同时计算事物,而不需要生成一个新线程的开销。
例如:
class Calculator {
public:
Calculator() : m_bDoneFlag( false ) {
for( auto& thread : m_arrayThreads )
{
thread = std::thread( [this]{
std::unique_lock<std::mutex> lockGuard( m_mutex, std::defer_lock );
while( !m_bDoneFlag )
{
lockGuard.lock();
m_condTaskWaiting.wait( lockGuard, [this]{ return !m_queueTasks.empty(); } );
std::packaged_task<void*()> packagedTask = std::move(m_queueTasks.front());
m_queueTasks.pop();
lockGuard.unlock();
// Execute task:
packagedTask();
}
});
}
}
~Calculator()
{
m_bDoneFlag = true;
std::unique_lock<std::mutex> lockGuard( m_mutex );
m_queueTasks.emplace( []{ std::this_thread::sleep_for( std::chrono::milliseconds(100) ); return nullptr; } );
m_queueTasks.emplace( []{ std::this_thread::sleep_for( std::chrono::milliseconds(100) ); return nullptr; } );
lockGuard.unlock();
m_condTaskWaiting.notify_all();
for( auto& thread : m_arrayThreads )
{
thread.join();
}
}
std::future<void*> AddTask( std::function<void*()> funcToAdd )
{
std::packaged_task<void*()> packagedTask( funcToAdd );
std::future<void*> future = packagedTask.get_future();
std::unique_lock<std::mutex> lockGuard( m_mutex );
m_queueTasks.emplace( std::move(packagedTask) );
lockGuard.unlock();
m_condTaskWaiting.notify_one();
return future;
}
private:
std::mutex m_mutex;
std::array<std::thread, 2> m_arrayThreads;
std::queue<std::packaged_task<void*()>> m_queueTasks;
std::condition_variable m_condTaskWaiting;
std::atomic<bool> m_bDoneFlag;
};
然后,您可以像这样使用它:
int main()
{
Calculator myCalc;
std::future<void*> future1 = myCalc.AddTask( []{ std::string* pszTest = new std::string("Test String"); return pszTest; } );
std::future<void*> future2 = myCalc.AddTask( []{ std::complex<float>* pcmplxTest = new std::complex<float>( 5.0f, 10.5f ); return pcmplxTest; } );
std::string* pszTest = reinterpret_cast<std::string*>(future1.get());
std::complex<float>* pcmplxTest = reinterpret_cast<std::complex<float>*>(future2.get());
std::cout << *pszTest << " and " << *pcmplxTest << std::endl;
delete pszTest;
delete pcmplxTest;
return 0;
}
显然,这没有我们想要的类型安全性,如果你可以缩小返回值的类型,你就可以显着提高类型安全性,你总是需要避免返回一个指向void
.