Как я могу объявить std :: thread анонимно?

Рассмотрим следующую короткую программу:

#include <thread>

int Foo() {
while (1);
}

int main(){
    std::thread t(Foo);
    std::thread s(Foo);

    // (std::thread(Foo));

    t.join();
}

Это компилируется и запускается (навсегда), с

g++ -Wl,--no-as-needed DoubleBufferTest.cc -o DoubleBufferTest -std=c++0x -pthread

В прокомментированной строке я пытаюсь использовать описанную здесь технику, чтобы анонимно анонсировать новую тему. Однако, когда эта строка будет прокомментирована, я могу скомпилировать, но запуск дает следующую ошибку:

terminate called without an active exception            
Aborted (core dumped)                                   

Как я могу анонимно объявить поток?

Заметьте, я на g++ 4.4.7.

Ответ 1

Вы можете сделать это следующим образом:

std::thread(Foo).detach();

Ответ 2

std::thread destructor вызовет std::terminate если поток не был соединен или отсоединен.

Поэтому, к сожалению, вы не можете создать анонимный объект потока, например: вам нужна ссылка на объект thread, чтобы вызвать либо join() либо detach().

Скотт Мейерс рассказал о Going Native 2013, где он создал класс RAII, который обертывает поток и вызывает соединение в деструкторе. Вы можете сделать что-то подобное:

class ThreadRAII {
public:
  ThreadRAII(std::thread&& thread): t(std::move(thread)) {}
  ~ThreadRAII() { if (t.joinable()) { t.join(); }

private:
  std::thread t;
};

См. Его сообщение в блоге или беседу для получения дополнительной информации.

Вы можете использовать его так

(ThreadRAII(std::thread(Foo)));

Однако единственной причиной, по которой вы хотите создать поток таким образом, является то, что вам все равно, когда (или если) оно закончится, поэтому в этом случае объединение не имеет большого смысла. Вместо этого вы должны изменить деструктор, чтобы отсоединить:

~ThreadRAII() { if (t.joinable()) { t.detach(); }

Как было предложено в комментариях, вы могли бы сделать его еще проще в использовании, совершенствуя пересылку во внутреннюю резьбу при строительстве:

class ThreadRAII2 {
public:    

    template <typename Func, typename ...Args>
    explicit ThreadRAII2(Func&& func, Args&&... args) :
        t(func, std::forward<Args>(args)...) {  }

    ~ThreadRAII2() { 
        if (t.joinable()) t.detach(); 
    }
private:
    std::thread t;
};

Тогда вы можете использовать его так же, как вы изначально хотели, без необходимости отсоединения:

(ThreadRAII2(Foo));

Или, если Foo принимает аргументы (например, Foo(int)):

(ThreadRAII2(Foo, 42));

Ответ 3

Я не думаю, что это (техника, о которой вы говорите) возможно с помощью потоков.

Взгляните сюда;

30.3.1.3 thread destructor [thread.thread.destr]

~ Нить();

Если joinable(), то terminate(), иначе никаких эффектов. [Примечание. Либо неявное разделение или объединение потока joinable() в его деструкторе может привести к ошибкам отладки (для отсоединения) или производительности (для объединения), возникающим только при возникновении исключения. Таким образом, программист должен убедиться, что деструктор никогда не выполняется, пока поток все еще соединен. - конечная нота]

В основном создаваемый вами временный анонимный объект (т.е. поток) разрушается, когда выполнение продолжается до следующей строки, которая нарушает вышеуказанное правило.