Сообщение std:: thread, чтобы убить/остановить себя при выполнении условия

Скажем, у меня есть рабочий поток tWorker, который инициализируется при построении Boss и сообщает ему, чтобы он выполнял work(), пока bRetired не будет истинным. std::mutex, mtx блокирует некоторые данные (vFiles), поэтому tWorker владеет им, когда он работает над ним.

Как мне сделать tWorker "совершить самоубийство" один раз bRetired становится true? Как будет mutex уничтожен, когда поток прекратит выполнение?

Я читал, что объекты std::thread не могут быть прерваны каким-либо образом. Не позволяет ли нить ничего (или вызывает std::this_thread::yield()) обеспечить тот же эффект, что и убийство потока?

class Boss {
private:
    std::thread tWorker;
    std::mutex mtx;
    bool bRetired;
    std::vector< std::string > vFiles;

    void work() {
        while ( bRetired == false ) {
            // Do your job!
            mtx.lock();
            // ... Do something about vFiles ...
            mtx.unlock();
        }

        // tWorker has retired, commit suicide
        // ** How? **

        // Does this suffice if I want to "kill" the thread?
        std::this_thread::yield(); 
    }

public:
    Boss() {
        bRetired = false;
        tWorker = std::thread( &Boss::work, this );

        // Have worker do its job independently
        // **Bonus Question** : Should this be tWorker.join() or tWorker.detach()?
        tWorker.detach();
    }

    retire() {
        bRetired = true;
    }
}

Примечания

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

Ответ 1

Вызов std::thread::yield() невозможен и не убивает вызывающий поток:

Предоставляет намек на реализацию, чтобы перенести выполнение потоков, позволяя запускать другие потоки.

Просто выйдите из функции, чтобы выйти из потока.

Обратите внимание, что использование bRetired неверно, так как два потока могут обращаться к одной и той же ячейке памяти, и один из этих потоков модифицирует ее: это поведение undefined. Кроме того, изменение, сделанное в функции retire(), другой поток, не будет видно нитью выполнения run(): use atomic<bool> для атомарности и видимости.

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

void retire() {
    bRetired = true;
    tWorker.join();
}

Используйте RAII для получения mutex es (std::lock_guard), чтобы гарантировать, что он всегда будет выпущен. mutex будет уничтожен, когда он выходит из области видимости, в этом случае, когда его содержащий класс разрушается.

Ответ 2

Как заставить tWorker "совершить самоубийство", как только bRetired станет истинным?

Вы позволяете потоку управления выйти из функции потока. Этот вызов std::this_thread::yield() не нужен.

Как бы мьютекс был уничтожен, когда поток прекратил выполнение?

Этот мьютекс является членом класса Boss. Он разрушается в деструкторе Boss, когда объект разрушается.

Я читал, что объекты std:: thread не могут быть прерваны каким-либо образом.

API С++ не предоставляет средства для завершения произвольного потока. Должен быть способ сказать потоку прекратить работу, а затем подождать, пока это произойдет, как вы намереваетесь сделать.

Разрешает ли поток ничего (или вызывает std:: this_thread:: yield()), чтобы тот же эффект, что и убийство потока?

Нет.

Однако существует условие гонки на переменной bRetired. Это либо должно быть std::atomic<bool>, либо его следует читать и изменять только тогда, когда этот мьютекс заблокирован.