Вывод программы появляется только иногда в многопоточной программе - PullRequest
0 голосов
/ 21 июня 2011

Я использую потоки повышения, чтобы распараллелить вычисления в моей программе.Контроллер управляет расчетными заданиями и результатами.Я создаю группу рабочих потоков, которые получают свои задания от объекта контроллера, в то время как основной поток отображает результаты.Результаты должны быть показаны в правильном порядке.Для достижения этого я использую фьючерсы на повышение в std::deque.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;
}

1 Ответ

2 голосов
/ 21 июня 2011

В случае, если вы не видите никакого вывода, он может выдать NoResultsLeft, потому что в первом проходе в очереди ничего нет. Другая возможность заключается в том, что он не может добавить что-либо в очередь или выбрасывает NoJobsLeft. Добавление операторов std::cout в ваши блоки catch может помочь определить, что происходит.

Однако, если результаты не могут отображаться асинхронно, то нет причины для механизма, который вы могли бы также подождать все. Порядок завершения потоков не гарантируется, только порядок, в котором вы добавляете результаты в очередь через boost::promise, так что вам все равно придется блокировать в GetNextResult, по крайней мере, до завершения первого потока.

Если вы хотите отображать результаты последовательно, ваш контроллер может собрать все результаты одинаковым образом и запустить boost::function, чтобы отобразить результаты в правильном порядке, когда все будет готово.

Изменить:

BTW while(!queue_.size()) действительно должно быть while(queue_.empty()), хотя технически все, что не равно нулю, интерпретируется как истинные методы с именами size(), length() и т. Д. Действительно выглядят безобразно при использовании в качестве условия if. То же самое касается return (queue_.size() || JobsLeft()) ? true : false;, который может быть return (!queue.empty() || JobsLeft());

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...