Как заново присоединить поток или дождаться завершения потока перед выходом - PullRequest
0 голосов
/ 22 апреля 2019

У меня есть приложение, которое подключается к сокету с помощью библиотеки asio. Мой основной поток вызывает open() для реализации сокета, где он затем отсоединяется от основного потока для продолжения выполнения.

Когда вызывается thread::detach(), поток больше не может быть присоединен, и, следовательно, вызывающая сторона не знает, когда поток завершил свое выполнение. Это приводит, по крайней мере, в моем приложении, к нечистому отключению. Ресурсы не освобождаются должным образом и только иногда приводят к сбою. Можно ли присоединиться к оторванной теме? Я хотел бы попытаться избежать использования условной переменной.

Вот мой пример:

io_socket io = new io_socket();

// The call to thread::detach() is done within io_socket::open()
io->open();

// Let some things happen...
std::this_thread::sleep_for(std::chrono::seconds(20));

// Safely kills all operations and resources before delete
io->close();

// A hack solution to allow time for the detached thread to do what it needs to do
//std::this_thread::sleep_for(std::chrono::milliseconds(1000));

// Crashes if I don't allow the detached thread to safely close
delete io;

return EXIT_SUCCESS;

Ответы [ 4 ]

2 голосов
/ 22 апреля 2019

Вы не можете снова прикрепить std::thread, который вы отсоединили.Единственный способ дождаться окончания потока отсоединения - использовать какую-то атомарную переменную / условие, чтобы уведомить вас, когда это будет сделано.

При этом вам, вероятно, не нужно отсоединять поток впервое место.Что вы можете сделать, так это создать хранилище для потоков, в которых вы будете жить (на ум приходит std::vector<std::thread>), а затем в open вы добавите новый поток в это хранилище.Как только вы все закончите, вы вызываете close, и close просматривает каждый поток в хранилище и вызывает join на нем.Это сделает close вашей точкой синхронизации, и после этого вы узнаете, что все потоки закончились, и вы можете безопасно закрыть приложение.

1 голос
/ 22 апреля 2019

Можно ли присоединиться к отсоединенной нити?

Нет. Это победило бы всю цель detach().

A t.detach() вызов на самом деле не делает ничего существенного. Единственная цель - отключить защитный механизм.

Обычно, если вы не detach() поток, то деструктор для объекта thread выдаст ошибку, если вы позволите объекту быть уничтоженным до того, как ваша программа join()ed его обнаружит. Единственная цель для этого - помочь вам избежать распространенной ошибки: она предназначена для предотвращения выхода и завершения вашей программы main() до завершения всех других потоков.

Цель t.detach() --- только цель - сказать библиотеке: «Спасибо, но я знаю, что делаю, мне не нужна помощь, и я НИКОГДА не собираюсь звонить t.join().


Если вы хотите, чтобы ваша программа вызывала t.join(), не звоните t.detach().

1 голос
/ 22 апреля 2019

Предполагая, что поток ввода-вывода закодирован вами, вы можете обработать это комбинацией std::promise и std::future, что-то вроде этого:

#include <chrono>
#include <thread>
#include <future>
#include <iostream>

using namespace std::chrono_literals;

void demo_thread (std::promise <bool> *p)
{
    std::cout << "demo thread waiting...\n";
    std::this_thread::sleep_for (1000ms);
    std::cout << "demo thread terminating\n";
    p->set_value (true);
}

int main ()
{
    std::promise <bool> p;
    std::thread t = std::thread (demo_thread, &p);
    t.detach ();

    // ...

    std::cout << "main thread waiting...\n";
    std::future <bool> f = p.get_future();
    f.wait ();

    std::cout << "main thread terminating\n";
}

Живая демоверсия

0 голосов
/ 22 апреля 2019

NathanOliver предоставил хороший ответ, но его решение может оказаться трудным, если функция io->open() не возвращает ссылку на объект std :: thread, который она создает (что, если она отсоединяется, скорее всего, нет). Если вы используете библиотеку Asio напрямую, я ожидаю, что io->close() должен правильно обрабатывать корректный выход потока перед удалением io. Однако, если вы реализовали эту оболочку, вам нужно либо вернуть ссылку на созданный объект потока в open(), либо изменить свою реализацию на close() так, чтобы она блокировалась до тех пор, пока ресурсы не были фактически освобождены. Кроме того, если эти методы реализованы самостоятельно, необходимо ли отключение в open()?

...