我正在寻找一种方法来等待一些工作完成,然后执行另一个完全不同数量的工作。当然还有线程。简要说明: 我创建了两个工作线程,都执行在io_service上运行。以下代码取自here。
为了简单起见,我创建了两种类型的作业, CalculateFib i CalculateFib2 。我希望 CalculateFib2 作业在 CalculateFib 作业完成之后之后启动。我尝试使用条件变量,如here所述,但如果CalculateFib2作业不止一个,程序就会挂起。我做错了什么?
thx,dodol#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
boost::mutex mx;
boost::condition_variable cv;
void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock();
io_service->run();
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
size_t fib( size_t n )
{
if ( n <= 1 )
{
return n;
}
boost::this_thread::sleep(
boost::posix_time::milliseconds( 1000 )
);
return fib( n - 1 ) + fib( n - 2);
}
void CalculateFib( size_t n )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Now calculating fib( " << n << " ) " << std::endl;
global_stream_lock.unlock();
size_t f = fib( n );
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] fib( " << n << " ) = " << f << std::endl;
global_stream_lock.unlock();
boost::lock_guard<boost::mutex> lk(mx);
cv.notify_all();
}
void CalculateFib2( size_t n )
{
boost::unique_lock<boost::mutex> lk(mx);
cv.wait(lk);
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Now calculating fib2( " << n << " ) " << std::endl;
global_stream_lock.unlock();
size_t f = fib( n );
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] fib2( " << n << " ) = " << f << std::endl;
global_stream_lock.unlock();
}
int main( int argc, char * argv[] )
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work( *io_service )
);
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] The program will exit when all work has finished."
<< std::endl;
global_stream_lock.unlock();
boost::thread_group worker_threads;
for( int x = 0; x < 2; ++x )
{
worker_threads.create_thread(
boost::bind( &WorkerThread, io_service )
);
}
io_service->post( boost::bind( CalculateFib, 5 ) );
io_service->post( boost::bind( CalculateFib, 4 ) );
io_service->post( boost::bind( CalculateFib, 3 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
work.reset();
worker_threads.join_all();
return 0;
}
答案 0 :(得分:2)
在CalculateFib2
内,您要做的第一件事就是等待条件(cv
)。此条件仅在CalculateFib
结束时发出信号。因此,除非条件被触发(通过发布CalculateFib
)作业,否则执行永远不会继续执行。
确实,添加任何其他类似的行:
io_service->post( boost::bind( CalculateFib, 5 ) );
io_service->post( boost::bind( CalculateFib, 4 ) );
io_service->post( boost::bind( CalculateFib, 3 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib, 5 ) ); // <-- ADDED
使执行运行完成。
努力提供更多亮点:如果你像(
)那样隔离一个Fib2批次(及时)io_service->post( boost::bind( CalculateFib, 5 ) );
io_service->post( boost::bind( CalculateFib, 4 ) );
io_service->post( boost::bind( CalculateFib, 3 ) );
boost::this_thread::sleep(boost::posix_time::seconds( 10 ));
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
io_service->post( boost::bind( CalculateFib2, 1 ) );
所有Fib2作业将始终阻止,无论线程数如何,因为Fib作业在发布之前都已退出。一个简单的
io_service->post( boost::bind( CalculateFib, 1 ) );
将解锁所有服务员(即只有等待线程的数量,这是可用线程的数量-1,因为Fib()作业也占用一个线程。现在有&lt; 7个线程这会死锁,因为甚至没有可用的线程来启动上的Fib()作业(所有线程都被阻止在Fib2中等待)
说实话,我没有得到你想要在调度方面实现的目标。我怀疑你应该监控工作队列,并且只有当你达到了所需的项目数量时才明确地发布工作('任务')。这样你就可以KISS并获得一个非常灵活的工作安排界面。
通常,对于线程组(池),您希望避免无限期地阻塞线程。这有可能使你的工作安排陷入僵局,否则表现不佳。