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

发布于 2024-11-16 08:01:39 字数 2647 浏览 1 评论 0原文

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

我的控制器类的重要部分:

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

I'm using boost threads to parallelize the calculations in my program. 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. GetNewJob() adds a new boost::promise to the end of the deque and returns a pointer. GetNextResult() takes a result from the front end of the queue. If no result is ready yet, it blocks the calling thread.

The important parts of my Controller class:

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.


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尛丟丟 2024-11-23 08:01:39

如果您没有看到任何输出,则可能会抛出 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());

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. The other possibility is that it is failing to add things to the queue in the first place or throwing NoJobsLeft. Adding std::cout statements into your catch blocks might help identify what's going on.

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.

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.

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. Same goes for return (queue_.size() || JobsLeft()) ? true : false; which could be return (!queue.empty() || JobsLeft());

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文