简体   繁体   English

程序输出有时仅出现在多线程程序中

[英]Program output appears only sometimes in multi-threaded program

I'm using boost threads to parallelize the calculations in my program. 我正在使用boost线程来并行化程序中的计算。 A controller object manages the calculation jobs and the results. 控制器对象管理计算作业和结果。 I create a bunch of worker threads which get their jobs from the controller object while the main thread displays the results. 我创建了一堆工作线程,当主线程显示结果时,它们从控制器对象获取作业。 The results need to be shown in the correct order. 结果需要以正确的顺序显示。 To achieve this I use boost futures in a std::deque . 为了达到这个目的,我在std::deque使用了boost期货。 GetNewJob() adds a new boost::promise to the end of the deque and returns a pointer. GetNewJob()在双端队列的末尾添加一个新的boost::promise并返回一个指针。 GetNextResult() takes a result from the front end of the queue. GetNextResult()从队列的前端获取结果。 If no result is ready yet, it blocks the calling thread. 如果还没有准备好结果,它会阻塞调用线程。

The important parts of my Controller class: 我的Controller类的重要部分:

class Controller
{
public:
    Controller();
    boost::shared_ptr<boost::promise<Results> > GetNewJob();
    Results GetNextResult();

    class NoJobsLeft{};
    class NoResultsLeft{};

private:
    bool JobsLeft() const;
    bool ResultsLeft() const;

    std::deque<boost::shared_ptr<boost::promise<Results> > > queue_;
    boost::mutex mutex_;
    boost::condition_variable condition_;
};

Worker function: 工人功能:

void DoWork()
{
    try
    {
        while(true)
        {
            boost::shared_ptr<boost::promise<Results> >
                    promise(controller.GetNewJob());

            //do calculations

            promise->set_value(results);
        }
    }
    catch(NoJobsLeft)
    {
    }
}

Main program code: 主程序代码:

Controller controller(args);

boost::thread_group worker_threads;

for (unsigned i = 0; i < n_cpus; ++i)
    worker_threads.create_thread(DoWork);

try
{
    while(true)
    {
        Results results = controller.GetNextResult();

        std::cout << results;
        std::cout << std::endl;
    }
}
catch(NoResultsLeft)
{
}

worker_threads.join_all();

Sometimes this works just fine, all results are displayed. 有时这很好用,所有结果都会显示出来。 But very often I cannot see any output at all. 但通常我根本看不到任何输出。

I do not use cout in the worker threads. 我不在工作线程中使用cout


Implementations of GetNewJob() , GetNextResult() : GetNewJob()GetNextResult()

boost::shared_ptr<boost::promise<Results> > Controller::GetNewJob()
{
    boost::lock_guard<boost::mutex> lock(mutex_);

    if (!JobsLeft())
        throw NoJobsLeft();

    //determine more information about the job, not important here

    queue_.push_back(boost::make_shared<boost::promise<Results> >());

    condition_.notify_one();

    return queue_.back();
}


Results Controller::GetNextResult()
{
    boost::shared_ptr<boost::promise<Results> > results;
    {
        boost::unique_lock<boost::mutex> lock(mutex_);

        if (!ResultsLeft())
            throw NoResultsLeft();

        while(!queue_.size())
        {
            condition_.wait(lock);
        }

        results = queue_.front();
        queue_.pop_front();
    }

    return results->get_future().get();
}

bool Controller::ResultsLeft() const
{
    return (queue_.size() || JobsLeft()) ? true : false;
}

In the case where you don't see any output it could be throwing NoResultsLeft because nothing is in the queue on the first pass. 如果您没有看到任何输出,则可能会抛出NoResultsLeft因为第一次传递队列中没有任何内容。 The other possibility is that it is failing to add things to the queue in the first place or throwing NoJobsLeft . 另一种可能性是它首先没有向队列添加内容或者抛出NoJobsLeft Adding std::cout statements into your catch blocks might help identify what's going on. std::cout语句添加到catch块中可能有助于识别正在发生的事情。

However if the results can't be displayed asynchronously then there is no reason for the mechanism you might as well wait all. 但是,如果结果无法异步显示,那么您没有理由等待所有这些机制。 There is no guarantee of the order of completion of threads only the order in which you add the results to the queue via boost::promise so you have to block anyway in GetNextResult at least until the first thread completes. 不能保证线程完成顺序只是通过boost::promise将结果添加到队列的顺序,所以你必须至少在GetNextResult中阻塞,直到第一个线程完成。

If you want to display results sequentially your controller could gather all results in the same way and fire a boost::function to display the results in the correct order when everything is ready. 如果要按顺序显示结果,控制器可以以相同的方式收集所有结果并触发boost::function ,以便在所有内容准备就绪时以正确的顺序显示结果。

Edit: 编辑:

BTW while(!queue_.size()) really ought to be while(queue_.empty()) while technically anything non-zero is interpreted as true methods named size() , length() , etc really look ugly when used as an if condition. BTW while(!queue_.size())真的应该是while(queue_.empty())而技术上任何非零被解释为名为size()真实方法, length()等在用作时非常丑陋如果条件。 Same goes for return (queue_.size() || JobsLeft()) ? true : false; return (queue_.size() || JobsLeft()) ? true : false; return (queue_.size() || JobsLeft()) ? true : false; which could be return (!queue.empty() || JobsLeft()); 哪个可以return (!queue.empty() || JobsLeft());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM