Поток как переменная-член класса - PullRequest
1 голос
/ 08 марта 2019

Я хотел бы держать поток в переменной-члене некоторого класса.Следующий фрагмент кода показывает, чего я хотел бы достичь:

#include <iostream>
#include <thread>
#include <vector>


class Test {

    public:
    std::thread& t;    
    Test(std::thread&& rt) : t(rt) {}    
};

int main()
{
    std::vector<Test> tests;

    {
        std::thread t ([]{
            std::cout << 1;
        });
        tests.push_back(Test(std::move(t)));
    }   

    for(Test mytest : tests)
    {
        mytest.t.join();
    }

}

Код будет разбит в строке join ().Ошибка:

terminate called without an active exception
Aborted (core dumped)

Почему я не могу вызвать поток через mytest.t, когда оставлена ​​область создания исходного потока?

Ответы [ 3 ]

6 голосов
/ 08 марта 2019

Поскольку std :: thread является подвижным, но не копируемым, вы можете сделать это так:

class Test {

public:
    std::thread t;
    Test(std::thread&& rt) : t(std::move(rt)) {}
};

int main()
{
    std::vector<Test> tests;

    {
        std::thread t([] {
            std::cout << 1;
        });
        tests.push_back(Test(std::move(t)));
    }

    for (Test& mytest : tests)
    {
        mytest.t.join();
    }

}
3 голосов
/ 08 марта 2019

В вашем классе у вас есть ссылка на поток, а не на объект потока:

std::thread& t;
           ^

Это означает, что произойдет следующая последовательность:

{
    std::thread t ([]{
        std::cout << 1;
    });                                  // 1. Thread is created.
    tests.push_back(Test(std::move(t))); // 2. Reference to moved thread is taken 
                                         // and after move thread is destroyed.
                                         // 3. Now the thread is destroyed, 
                                         // but not joined which will call `std::terminate` 
                                         // (Thanks @tkausl)
}   

Если вы сделаете свой класс std::thread t ход будет работать.

0 голосов
/ 08 марта 2019

Как уже упоминалось @tkausl, что это ссылка, {} уничтожает объект потока, как только он выходит из области видимости, и ваша ссылка больше не действительна. Кроме того, вам нужно изменить ваш цикл так, чтобы он не создавал копию исходного объекта Test. После модификаций это становится:

class Test {

    public:
    std::thread& t;    
    Test(std::thread&& rt) : t(rt) {}    
};

int main()
{
    std::vector<Test> tests;


    std::thread t ([]{
        std::cout << 1;
    });
    tests.push_back(Test(std::move(t)));

    for(Test& mytest : tests)
    {
        mytest.t.join();
    }
}
...