Как бы я остановил std :: thread контролируемым образом? - PullRequest
0 голосов
/ 28 января 2019

У меня есть программа, в которой я запускаю несколько долго работающих потоков (например, REST-API).На загрунтованных сигналах (например, SIGHUP) я хотел бы иметь возможность аккуратно завершить все потоки (ожидая их выхода).Ниже следует некоторый код из статьи thispointer , в которой проиллюстрирована хорошая идея о том, как это сделать

#include <thread>
#include <iostream>
#include <assert.h>
#include <chrono>
#include <future>

void threadFunction(std::future<void> futureObj)
{
     std::cout << "Thread Start" << std::endl;
     while (futureObj.wait_for(std::chrono::milliseconds(1)) == 
 std::future_status::timeout)
    {
        std::cout << "Doing Some Work" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    }
    std::cout << "Thread End" << std::endl;

}
int main()
{

    // Create a std::promise object
    std::promise<void> exitSignal;

    //Fetch std::future object associated with promise
    std::future<void> futureObj = exitSignal.get_future();

    // Starting Thread & move the future object in lambda function by reference
    std::thread th(&threadFunction, std::move(futureObj));

    //Wait for 10 sec
    std::this_thread::sleep_for(std::chrono::seconds(10));

    std::cout << "Asking Thread to Stop" << std::endl;

    //Set the value in promise
    exitSignal.set_value();

    //Wait for thread to join
    th.join();

    std::cout << "Exiting Main Function" << std::endl;
    return 0;
}

Однако, как можно было заметить, эта концепция имеет критический недостаток: exitSignal должен быть выпущен до вызова th.join().

В ситуации, когда кто-то хочет прослушать сигнал, например, используя signal(SIGHUP, callback), это, конечно, нецелесообразно.

Мой вопросесть: есть ли лучшие концепции для отключения нескольких потоков?Как бы я пошел о них?Я думаю, что использование promise - неплохая идея, я просто не нашел способ решить мою проблему.

1 Ответ

0 голосов
/ 28 января 2019

Вы можете использовать std :: notify_all_at_thread_exit () для std :: condition_variable.
Вот пример:

#include <mutex>
#include <thread>
#include <condition_variable>

#include <cassert>
#include <string>

std::mutex m;
std::condition_variable cv;

bool ready = false;
std::string result; // some arbitrary type

void thread_func()
{
    thread_local std::string thread_local_data = "42";

    std::unique_lock<std::mutex> lk(m);

    // assign a value to result using thread_local data
    result = thread_local_data;
    ready = true;

    std::notify_all_at_thread_exit(cv, std::move(lk));

}   // 1. destroy thread_locals;
    // 2. unlock mutex;
    // 3. notify cv.

int main()
{
    std::thread t(thread_func);
    t.detach();

    // do other work
    // ...

    // wait for the detached thread
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [] { return ready; });

    // result is ready and thread_local destructors have finished, no UB
    assert(result == "42");
}

Источник: cppreference.com

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...