C++11 packaged_task, работающий со своим собственным потоком, нуждается в join(), чтобы получить будущее

Из книги C++11, которую я недавно получил, я пытаюсь построить пример на странице 123 (packaged_task 5.3.5.2), и после нескольких вещей, чтобы это работало с XCode, у меня есть пара вопросов:

Во-первых, кажется, что существует требование передать указатель на функцию в пакет packaged_task. Текст не показывает амперсанд, так что, может быть, это опечатка или изменение в конце стандарта?

Затем, и что более важно, мне пришлось добавить thread.join (s), чтобы можно было вызывать get и избегать sigabrt, и процесс завершается без печати чего-либо. У меня сложилось впечатление, что вызов get будущего будет блокироваться до тех пор, пока поток не вернет значение, но, похоже, это не так. Добавление объединения также, кажется, игнорирует асинхронную (неблокирующую) природу кода. Почему нельзя в будущем сделать само соединение, если это необходимо? Читая из документов, он говорит, что get будет вызывать неявное ожидание, и даже если добавить код в ожидании, это все равно вызывает sigabrt. Это очень загадочно.

Я использую диалект языка c11, -std=gnu++11 и libC++ (с поддержкой C++11). Я попробовал другие варианты без удачи (при использовании gnuC++ он не может найти). Кажется, это единственные комбинации, которые я могу использовать для создания кода. XCode очень требователен к тому, что нужно для компиляции C++11.

Заранее благодарны за Вашу помощь.

Вот тестовый пример из книги с моими "исправлениями" для запуска кода:

    #include <iostream>
    #include <numeric>
    #include <vector>
    #include <thread>
    #include <future>

    using namespace std;

    double accum(double *beg, double *end, double init)
    {
        return accumulate(beg, end, init);
    }

    double comp2(vector<double>& v)
    {

        using Task_type = double(double*,double*,double);

        packaged_task<Task_type> pt0 {&accum}; //use '&' to compile
        packaged_task<Task_type> pt1 {&accum}; //use '&' to compile

        future<double> f0 {pt0.get_future()};
        future<double> f1 {pt1.get_future()};

        double* first=&v[0];
        thread t1 {move(pt0), first, first+v.size()/2, 0};
        thread t2 {move(pt1), first+v.size()/2, first+v.size(), 0};

        // need this to run
        t1.join(); 
        t2.join();

        // using this instead of the join doesn't work
//      f0.wait(); 
//      f1.wait();

        return f0.get() + f1.get();
    }

    int main()
    {
        vector<double> v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        cout<<comp2(v)<<endl;
        return 0;
    }

3 ответа

Решение

Вам необходимо либо отсоединить, либо присоединить каждый объект потока перед его уничтожением. Если вы используете фьючерсы, я ожидаю, что у потоков будет значительно более длительный срок службы, чем у фьючерсов.

Вам нужно вызвать join() в потоке или отсоединить его. Это вопрос? В этом случае packaged_task может использоваться для обеспечения безопасности исключений, но у вас все еще есть пара потоков, которые запускают шоу.

Я думаю, что текущие ответы не ответили на вопрос напрямую. Вам не нужно явно создавать потоки для запуска задач. Например:

#include <future>
#include <stdexcept>
#include <iostream>
#include <thread>
#include <utility>
#include <functional>

using namespace std;

int ff(int i)
{
  return i;
}

int main(int argc, char *argv[])
{

  packaged_task<int(int)> pt1 (ff);
  auto v1 = pt1.get_future();
  thread t1(move(pt1), 1);
  t1.join();

  packaged_task<int(int)> pt2(ff);
  auto v2 = pt2.get_future();
  pt2(1);
  cout << v2.get() << endl;

  return 0;
}

Если вы скомпилируете приведенный выше пример, вы увидите 1 как стандартный вывод.

Но что меня смутило, так это то, что если я закомментирую первый packaged_task, то вижу std::system_error, полный код:

#include <future>
#include <stdexcept>
#include <iostream>
#include <thread>
#include <utility>
#include <functional>

using namespace std;

int ff(int i)
{
  return i;
}

int main(int argc, char *argv[])
{

  // packaged_task<int(int)> pt1 (ff);
  // auto v1 = pt1.get_future();
  // thread t1(move(pt1), 1);
  // t1.join();

  packaged_task<int(int)> pt2(ff);
  auto v2 = pt2.get_future();
  pt2(1);
  cout << v2.get() << endl;

  return 0;
}

Очевидно, что два packaged_tasks являются независимыми, и, тем не менее, удаление первого вызовет сбой второго с system_error,

Это не ответ на вопрос, а попытка уточнить вопрос.

Другие вопросы по тегам