Std:: thread - "завершение вызова без активного исключения", не хотите "присоединяться" к нему

В соответствии с Этот вопрос, я использую поток для завершения функции при вводе пользователя. Мой код выглядит примерно так:

bool stopper = false;
thread stopThread(userStop, &stopper);      // start thread looking for user input
for(int i = 0; i < 1000; i++) {
    if(stopper) { break; }                  // break if desired
    // Do stuff
}
return 0;

где

userStop(bool *st) {
    char chChar = getchar();
    if(chChar == '\n') {
        *st = true;
    }
}

Когда я запускаю это, я получаю сообщение об ошибке terminate called without an active exception. Исходя из этих вопросов: поток завершает вызов без активного исключения, С++ завершает вызов без активного исключения; это похоже на то, что я не "снова присоединяюсь к потоку".

Проблема в том, что я не хочу "присоединяться" к потоку, потому что тогда пользователю нужно, чтобы предоставить вход для userStop() для завершения, но я хочу, чтобы пользователь только введите вход, если прерывание for-loop должно быть нарушено (что необязательно).

Спасибо!

Ответы

Ответ 1

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

30.3.1.3 thread destructor [thread.thread.destr]

~ нить();

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

Это означает, что вы не должны позволить потокам выйти из области действия без предварительного вызова либо join(), либо detach().

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

  • Этот поток теперь полностью отвечает за собственное время жизни. Если он не возвращается сам по себе, он будет работать вечно (пока процесс не завершится).

  • Вы получаете пользовательский ввод, предположительно, из-за чего-то вроде cin или getch(). Если к ним обращаются из нескольких потоков, у вас нет достаточной уверенности в том, что в их библиотечных реализациях нет условий гонки. Протектор слегка.

Ответ 2

В стандартном потоке ввода вы будете асинхронно читать с ввода. И просыпайтесь как по требованию, чтобы прекратить чтение, так и новый ввод.

Прекращение нити без соединения не является разумной вещью. Итак, что вам нужно сделать, это сказать "yo thread, закончить прямо сейчас", а затем ожидать, что соединение завершится быстро. Это может быть даже через двухступенчатое рукопожатие ( "yo thread, finish up", а затем "ok ok, мне удалось очистить, присоединяйтесь ко мне сейчас" ) в некоторых случаях.

Обратите внимание, что ваш цикл до 1000 выглядит действительно смешно: таймауты ввода пользователя обычно должны основываться на фактическом прохождении времени или на каком-то другом событии, которое делает вход пользователя не полезным.

Ответ 3

Прекращение потока - плохая идея - вы должны сделать ваш поток изящным. Если вы закончили поток, вы в конечном итоге вызываете код в функции getch(), чтобы неожиданно закончиться. Что делать, если этот код находился в середине управления структурой данных, выделения или освобождения памяти или выполнения некоторых других работ, которые выполнялись до завершения? В конечном итоге вы оставите что-то в недопустимом состоянии, и вы в конечном итоге потерпите крах, когда это недопустимое состояние будет выполнено.