Подтвердить что ты не робот

Как проверить, работает ли std:: thread?

Как проверить, работает ли std::thread (независимо от платформы)? Он не имеет метода timed_join() и joinable() для этого не предназначен.

Я думал о блокировке мьютекса с std::lock_guard в потоке и с помощью метода try_lock() мьютекса, чтобы определить, все ли он заблокирован (поток работает), но мне кажется излишне сложным.

Знаете ли вы более элегантный метод?

Обновление: Чтобы быть ясным: я хочу проверить, прошел ли поток с чистотой или нет. Для этой цели считается "висячей" нитью.

4b9b3361

Ответ 1

Если вы хотите использовать С++ 11 std::async и std::future для выполнения своих задач, вы можете использовать функцию wait_for std::future, чтобы проверить, работает ли поток в аккуратный способ:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    /* Run some task on new thread. The launch policy std::launch::async
       makes sure that the task is run asynchronously on a new thread. */
    auto future = std::async(std::launch::async, [] {
        std::this_thread::sleep_for(3s);
        return 8;
    });

    // Use wait_for() with zero milliseconds to check thread status.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    auto result = future.get(); // Get result.
}

Если вы должны использовать std::thread, вы можете использовать std::promise для получения будущего объекта:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a promise and get its future.
    std::promise<bool> p;
    auto future = p.get_future();

    // Run some task on a new thread.
    std::thread t([&p] {
        std::this_thread::sleep_for(3s);
        p.set_value(true); // Is done atomically.
    });

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

Оба этих примера будут выводиться:

Thread still running

Это, конечно, потому, что статус потока проверяется до завершения задачи.

Но опять же, проще было бы просто сделать это, как уже говорили другие:

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::atomic<bool> done(false); // Use an atomic flag.

    /* Run some task on a new thread.
       Make sure to set the done flag to true when finished. */
    std::thread t([&done] {
        std::this_thread::sleep_for(3s);
        done = true;
    });

    // Print status.
    if (done) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

Edit:

Также существует std::packaged_task для использования с std::thread для более чистого решения, чем при использовании std::promise:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a packaged_task using some task and get its future.
    std::packaged_task<void()> task([] {
        std::this_thread::sleep_for(3s);
    });
    auto future = task.get_future();

    // Run task on new thread.
    std::thread t(std::move(task));

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        // ...
    }

    t.join(); // Join thread.
}

Ответ 2

Простое решение состоит в том, чтобы иметь логическую переменную, которую поток устанавливает в true с регулярными интервалами, и это проверяется и устанавливается в false потоком, который хочет знать статус. Если переменная имеет значение false для long, то поток больше не считается активным.

Более потокобезопасным способом является наличие счетчика, который увеличивается потоком дочернего потока, а основной поток сравнивает счетчик с сохраненным значением, а если он слишком длительный, то дочерний поток считается неактивным.

Обратите внимание, что в С++ 11 нет способа фактически убить или удалить зависающий поток.

Изменить. Как проверить, прошел ли поток извне, или нет: в основном такой же метод, как описано в первом абзаце; Булева переменная инициализируется значением false. Последнее, что делает дочерний поток, задано как true. Затем основной поток может проверить эту переменную, и если true делает соединение в дочернем потоке без значительного (если есть) блокировки.

Edit2 Если поток выходит из-за исключения, то имеет две "основные" функции: первый имеет try - catch, внутри которого он вызывает второй "реальный", функция основного потока. Эта первая основная функция устанавливает переменную "has_exited". Что-то вроде этого:

bool thread_done = false;

void *thread_function(void *arg)
{
    void *res = nullptr;

    try
    {
        res = real_thread_function(arg);
    }
    catch (...)
    {
    }

    thread_done = true;

    return res;
}

Ответ 3

Создайте мьютекс, к которому имеют доступ текущий поток и вызывающий поток. Когда запущенный поток запускает, он блокирует мьютекс, а когда он заканчивается, он блокирует мьютекс. Чтобы проверить, продолжает ли поток, вызывающий поток вызывает mutex.try_lock(). Возвращаемым значением является статус потока. (Просто убедитесь, что разблокировать мьютексы, если try_lock работал)

Одна небольшая проблема с этим, mutex.try_lock() вернет ложь между временем создания потока и блокировкой мьютекса, но этого можно избежать, используя несколько более сложный метод.

Ответ 4

Конечно, переменная, обернутая мьютексом, инициализирована до false, что поток устанавливает значение true как последнее, что он делает до выхода. Этот атом достаточно для ваших нужд?

Ответ 5

Этот простой механизм, который вы можете использовать для обнаружения завершения потока без блокировки в методе объединения.

std::thread thread([&thread]() {
    sleep(3);
    thread.detach();
});

while(thread.joinable())
    sleep(1);