Как остановить выполнение потока в C ++ - PullRequest
1 голос
/ 24 апреля 2019

Я создал один поток в моей основной программе, выполнение потока должно быть остановлено после завершения основной программы. Я использую reader.join();, чтобы прекратить выполнение потока. Но это не останавливает казнь.

Я пытался использовать приведенный ниже код, я использую функцию thread.join();, но завершить поток не удалось. И после основной программы мой поток продолжает выполняться.

#include <algorithm>
#include <array>
#include <atomic>
#include <mutex>
#include <queue>
#include <cstdint>
#include <thread>
#include <vector>

using namespace std;
using namespace std::chrono;

typedef pair<int, Mat> pairImage;

class PairComp {
public:
    bool operator()(const pairImage& n1, const pairImage& n2) const
    {
        if (n1.first == n2.first)
            return n1.first > n2.first;
        return n1.first > n2.first;
    }
};

int main(int argc, char* argv[])
{
    mutex mtxQueueInput;
    queue<pairImage> queueInput;
    int total = 0;
    atomic<bool> bReading(true);
    thread reader([&]() {
        int idxInputImage = 0;
        while (true) {
            Mat img = imread("img_folder/");
            mtxQueueInput.lock();
            queueInput.push(make_pair(idxInputImage++, img));
            if (queueInput.size() >= 100) {
                mtxQueueInput.unlock();
                cout << "[Warning]input queue size is " << queueInput.size();
                // Sleep for a moment
                sleep(2);
            }
            else {
                mtxQueueInput.unlock();
            }
        }
        bReading.store(false);
    });

    while (true) {
        pair<int, Mat> pairIndexImage;
        mtxQueueInput.lock();
        if (queueInput.empty()) {
            mtxQueueInput.unlock();
            if (bReading.load())
                continue;
            else
                break;
        }
        else {
            // Get an image from input queue
            pairIndexImage = queueInput.front();
            queueInput.pop();
        }
        mtxQueueInput.unlock();
        cv::Mat frame = pairIndexImage.second;

        cv::rectangle(frame, cv::Rect{ 100, 100, 100, 100 }, 0xff);
    }

    cv::imshow("out_image", frame);
    waitKey(1);

    if (total++ == 200)
        break;

    if (reader.joinable()) {
        reader.join();
    }

    return 0;
}

Ответы [ 3 ]

4 голосов
/ 24 апреля 2019

thread.join() не приводит к завершению потока, а ожидает окончания потока.Поток несет ответственность за завершение своего выполнения, например, путем периодической проверки определенного условия, например, флага.

У вас уже есть флаг atomic bReading, который, по-видимому, заставляет потоквыход.

        if (queueInput.empty()) {
            mtxQueueInput.unlock();
            if (bReading.load())
                continue;
            else
                break;  // thread will exit when queue is empty and bReading == false

Так что все, что вам нужно, это установить bReading = false во внешнем потоке перед вызовом thread.join().

bReading = false;
reader.join();

Обратите внимание, что bReading.store(false); внутри вашей темы не будет иметь никакого эффекта.


Примечание: вам не нужно вызывать atomic.load() и atomic.store(), вы можете просто использовать их в своем коде, который будет вызывать load()и store() неявно.

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

Мне не известна встроенная возможность остановить thread.Поскольку у вас есть endless-loop, встроенный в ваш поток, он не остановится в любое время.

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

  • A bool переменная, которую вы устанавливаете false, когда thread должен выйти.например while(run) или что-то подобное;для простоты вы также можете использовать std::atomic<bool>
  • переменную сигнализации, которую вы проверяете.std::condition_variable

То, что вы делаете в данный момент, заключается в том, что вы ожидаете в своем main-thread, что ваш thread завершается.Так как std::thread::join не завершает ваш thread, ваш main-thread будет выполняться вечно.

ПРИМЕЧАНИЕ. Когда вы решите внедрить решение bool.Вы должны защитить это bool с помощью mutex или чего-то подобного.

Спасибо за комментарий.Поскольку я не хочу указывать всем на boost, но вы упомянули это.Найти информацию здесь .

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

Проблема не в join, который (кстати) не предназначен для остановки или завершения потока.

Функция, которую выполняет ваш поток, содержит while(true), который никогда не прекратит работу, потому что он может только спать и разблокировать блокировку, ничего больше.

Это означает, что bReading.store никогда не будетвызываться и, как следствие, в цикле основного потока вы всегда будете идти, хотя эта ветвь имеет значение

if (bReading.load())
        continue;

, означающее, что также main будет выполняться вечно.


std::join используется для ожидания потока, что другой поток завершил свою работу.когда вы выполняете thread1.join() из потока main, происходит следующее: main будет ждать до тех пор, пока thread1 не завершит свое выполнение перед выполнением любой другой инструкции.

...