【问题标题】:Program output appears only sometimes in multi-threaded program程序输出只出现在多线程程序中
【发布时间】:2011-06-21 10:32:26
【问题描述】:

我正在使用 boost 线程来并行化我的程序中的计算。控制器对象管理计算作业和结果。我创建了一堆工作线程,它们从控制器对象获取它们的工作,而主线程显示结果。结果需要以正确的顺序显示。为了实现这一点,我在std::deque 中使用了 boost 期货。 GetNewJob() 在双端队列的末尾添加一个新的 boost::promise 并返回一个指针。 GetNextResult() 从队列的前端获取结果。如果还没有准备好结果,它会阻塞调用线程。

我的 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_;
};

工人函数:

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

            //do calculations

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

主程序代码:

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();

有时这很好用,所有结果都会显示出来。 但很多时候我根本看不到任何输出。

我不在工作线程中使用cout


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;
}

【问题讨论】:

  • @Fredrik: std::endl 隐式刷新流。
  • 那我今天学到了新东西!谢谢
  • 你能告诉我们GetNewJob()GetNextResult()函数的实现吗?

标签: c++ multithreading boost-thread cout


【解决方案1】:

如果您看不到任何输出,它可能会抛出 NoResultsLeft,因为在第一次传递时队列中没有任何内容。另一种可能性是它未能首先将内容添加到队列中或抛出NoJobsLeft。将 std::cout 语句添加到您的 catch 块中可能有助于确定发生了什么。

但是,如果结果不能异步显示,那么没有任何理由让你等待所有的机制。无法保证线程的完成顺序,只能保证您通过boost::promise 将结果添加到队列中的顺序,因此您必须至少在第一个线程完成之前在GetNextResult 中阻塞。

如果您想按顺序显示结果,您的控制器可以以相同的方式收集所有结果并触发boost::function,以便在一切准备就绪后以正确的顺序显示结果。

编辑:

顺便说一句,while(!queue_.size()) 真的应该是 while(queue_.empty()),而从技术上讲,任何非零值都被解释为名为 size()length() 等的真正方法,当用作 if 条件时,它们看起来真的很难看。 return (queue_.size() || JobsLeft()) ? true : false; 也是如此,可能是 return (!queue.empty() || JobsLeft());

【讨论】:

  • 谢谢,NoResultsLeft 的想法是对的。由于我在初始化JobsLeft() 中使用的变量时犯了一个错误,所以它在一开始就被抛出了。这导致JobsLeft() 在开始时返回false。但是现在我遇到了一次似乎无法重现的僵局。我会让程序在夜间循环运行,看看它是否会发生。还要感谢其他提示,尤其是三元运算符。我想知道为什么我没有看到这个:)
  • 我不太明白你的第二段。能否请您再次解释一下?
  • 要点是因为您希望按照启动顺序而不是完成顺序显示结果,您可以通过等待所有线程完成然后只处理结果并在之后显示。
  • 是的,我也想过这个。但是如果我这样实现它并且我想执行大量计算,我可能会耗尽内存。所以我决定直接把它放到stdout,从那里可以重定向到一个文件。
  • 好吧,你需要足够的内存来执行所有计算,因为所有线程都在范围内,直到你到达join_all调用之后cout,看起来你' 最初只产生与 CPU 一样多的线程,因此在您的计算中没有出现失控的内存泄漏,我怀疑这将是一个问题。不过,这只是一个简单的建议。
猜你喜欢
  • 1970-01-01
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 1970-01-01
相关资源
最近更新 更多