提升asio需要在m个工作完成后才发布n个工作

时间:2011-10-16 22:44:25

标签: c++ multithreading boost boost-asio boost-thread

我正在寻找一种方法来等待一些工作完成,然后执行另一个完全不同数量的工作。当然还有线程。简要说明: 我创建了两个工作线程,都执行在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;
}

1 个答案:

答案 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并获得一个非常灵活的工作安排界面。

通常,对于线程组(池),您希望避免无限期地阻塞线程。这有可能使你的工作安排陷入僵局,否则表现不佳。