Кажется, я получаю другое поведение назначения объекта потока между потоками boost и std. Если я использую потоки ускорения, переменную члена потока можно переназначить, а поток воссоздать. Если я использую потоки std, я получаю ошибку времени выполнения terminate called without an active exception.
Вот код, о котором идет речь (запустите, затем замените std :: на boost: :)
class ThreadTest
{
private:
std::thread mythread;
std::atomic<bool> running_;
int doSomeWork(){
int i=0;
cout << "starting" << endl;
while(running_){
cout << "working" << endl;
std::this_thread::sleep_for (std::chrono::seconds(1));
if (i>3){ break; } else { i++; }
}
running_ = false;
}
public:
void runThread(){
running_ = true;
mythread = std::thread(&ThreadTest::doSomeWork, this);
}
void joinThread(){
mythread.join();
}
};
int main(){
ThreadTest test;
test.runThread();
std::this_thread::sleep_for (std::chrono::seconds(10));
test.runThread();
test.joinThread();
return 0;
}
Выход для наддува:
starting
working
working
working
working
working
starting
working
working
working
working
working
Вывод для std ::
starting
working
working
working
working
working
terminate called without an active exception
Aborted (core dumped)
Этот конкретный фрагмент кода используется в библиотеке, которая, похоже, не имеет повышения как зависимости. Я хотел бы сохранить это таким образом, так есть ли способ получить поведение повышения «переназначения» с помощью потоков std?
РЕДАКТИРОВАТЬ - РЕШЕНИЕ
Я добавил std::atomic<bool> threadInitialized_; в класс, для которого задано значение true в функции потока doSomeWork(). Мой метод runThread() становится:
void runThread(){
if (threadInitialized_)
mythread.join();
running_ = true;
mythread = std::thread(&ThreadTest::doSomeWork, this);
}
Я знаю, что это заблокирует основной поток, пока не будет создан порожденный поток.
@SidS Я хотел бы знать, есть ли способ повторно использовать его, а если нет, то какой эквивалентный способ std :: thread делать то, что я пытаюсь сделать
Поскольку boost 1.50, boost::thread и std::thread должны вести себя в этом отношении одинаково. Существует макрос препроцессора, который вы можете определить, чтобы вернуться к старому поведению, но он не используется по умолчанию.
Помимо технических проблем, есть еще одна вещь, которая вас укусит: похоже, у вас несбалансированные вызовы runThread () и joinThread (), и вы ожидаете, что это сработает! Для меня это показатель того, что ваш код смешивает обязанности. Если этот класс отвечает за поддержку фоновой службы, возложите на него полную ответственность за это. Игнорировать запросы на запуск, когда службы работают, и игнорировать запросы на завершение работы, если это не так. Между тем, необходимый перезапуск потока должен оставаться обязанностью этого класса, а не кого-либо еще.
@UlrichEckhardt joinThread () существует только для целей этого примера, иначе моя основная функция вернется, и я не получу вывода. Спасибо за ваш вклад, может быть, он пригодится кому-то другому! В моем реальном коде я проверяю, запущен ли уже поток, и игнорирую запрос, если он есть.





От std :: thread :: operator = ()
«Если [объект потока] может быть присоединен, вызывается terminate ()».
Понятно, есть ли способ сделать то, что я пытаюсь сделать, кроме использования какого-то пула потоков?
Перед повторным использованием объекта std::thread необходимо остановить или отсоединить поток.
Вы можете заставить функцию потока ждать какого-то сигнала, чтобы выполнить дополнительную работу, вместо того, чтобы возвращаться.
Хорошо, спасибо за идеи - я думаю, что мне нужно воссоздать поток, потому что ему нужно перезапустить соединение с сокетом. Завершение потока происходит, когда получены неверные данные или сокет каким-либо образом завершен.
Как правило, как правильно указано выше, все (присоединяемые) потоки должны быть объединены или отсоединены до того, как их объект будет уничтожен.
Одно (из многих) различий между потоками Boost и std :: thread заключается в том, что потоки Boost отделяются внутри своего деструктора, чего не делают std :: thread; поэтому ваше неправильное использование std :: thread правильно запускает terminate ().
PS: НЕ (!!) верьте другим комментаторам выше, что std :: thread и boost :: thread должны вести себя «одинаково» - это просто неправда!
«Потоки Boost отключаются внутри своего деструктора» - эта функция теперь устарела, см. boost.org/doc/libs/1_66_0/doc/html/thread/….
Приведите доказательства. Связанная документация говорит об обратном. (Цитата: Причина перехода на std::terminate заключается в том, что либо неявное отключение, либо присоединение к потоку joinable() в его деструкторе может привести к трудным для отладки ошибкам корректности (для detach) или производительности (для join), возникающим только при возникновении исключения. Таким образом, программист должен гарантировать, что деструктор никогда не будет выполняться, пока поток все еще может быть присоединен. Присоединитесь к цепочке перед удалением или используйте цепочку с заданной областью действия.).
При использовании boost :: thread, если вы явно не вызываете join () или detach (), тогда деструктор boost :: thread и оператор присваивания вызовут detach () для объекта потока, который уничтожается / назначается соответственно. Для объекта std :: thread C++ 11 это приведет к вызову std :: terminate () и прерыванию приложения. В этом случае вам нужно вызвать detach () или join () вручную.
Что заставляет вас думать, что
std::threadможно использовать повторно?