Timeout per thread.join()

Timeout per thread.join()

Non c'è timeout per std::thread::join() . Tuttavia puoi visualizzare std::thread::join() come semplice funzione di convenienza. Usando condition_variable s puoi creare una comunicazione e una cooperazione molto ricche tra i tuoi thread, comprese le attese a tempo. Ad esempio:

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

int thread_count = 0;
bool time_to_quit = false;
std::mutex m;
std::condition_variable cv;

void f(int id)
{
    {
    std::lock_guard<std::mutex> _(m);
    ++thread_count;
    }
    while (true)
    {
        {
        std::lock_guard<std::mutex> _(m);
        std::cout << "thread " << id << " working\n";
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(250));
        std::lock_guard<std::mutex> _(m);
        if (time_to_quit)
            break;
    }
    std::lock_guard<std::mutex> _(m);
    std::cout << "thread ended\n";
    --thread_count;
    cv.notify_all();
}

int main()
{
    typedef std::chrono::steady_clock Clock;
    std::thread(f, 1).detach();
    std::thread(f, 2).detach();
    std::thread(f, 3).detach();
    std::thread(f, 4).detach();
    std::thread(f, 5).detach();
    auto t0 = Clock::now();
    auto t1 = t0 + std::chrono::seconds(5);
    std::unique_lock<std::mutex> lk(m);
    while (!time_to_quit && Clock::now() < t1)
        cv.wait_until(lk, t1);
    time_to_quit = true;
    std::cout << "main ending\n";
    while (thread_count > 0)
        cv.wait(lk);
    std::cout << "main ended\n";
}

In questo esempio main avvia diversi thread per funzionare, tutti occasionalmente controllano se è ora di uscire sotto un mutex (questo potrebbe anche essere un atomico). Il thread principale controlla anche se è il momento di uscire (se i thread portano a termine tutto il loro lavoro). Se main esaurisce la pazienza, dichiara semplicemente che è ora di uscire, quindi attende che tutti i thread eseguano la pulizia necessaria prima di uscire.


Sì, è possibile. La soluzione suggerita da Galik si presenta così:

#include <thread>
#include <future>
...
// Launch the thread.
std::thread thread(ThreadFnc, ...);
...
// Terminate the thread.
auto future = std::async(std::launch::async, &std::thread::join, &thread);
if (future.wait_for(std::chrono::seconds(5)) 
    == std::future_status::timeout) {

  /* --- Do something, if thread has not terminated within 5 s. --- */

}

Tuttavia, questo essenzialmente avvia un terzo thread che esegue il thread.join() .

(Nota:il distruttore di future bloccherà fino a thread si è unito e il thread ausiliario è terminato.)

Forse avviare un thread solo per portare giù un altro thread non è quello che vuoi. C'è un'altra soluzione portatile senza un thread ausiliario:

#include <thread>
#include <future>
...
// Launch the thread.
std::future<T_return>*  hThread 
  = new std::future<T_return>(std::async(std::launch::async, ThreadFnc, ...));
...
// Terminate the thread.
if (hThread->wait_for(std::chrono::seconds(5)) 
    == std::future_status::timeout) {

  /* --- Do something, if thread has not terminated within 5 s. --- */

} else
  delete hThread;

dove T_return è il tipo di ritorno della tua procedura di thread. Questo scenario utilizza un std::future / std::async combinazione invece di un std::thread .

Nota che hThread è un puntatore. Quando chiami il delete operatore su di esso, invocherà il distruttore di *hThread e blocca finché il thread non è terminato.

Ho testato entrambe le versioni con gcc 4.9.3 su Cygwin.


Invece di usare i thread in modo esplicito puoi usare std::async() per fornirti un std::future<> e puoi fare attese a tempo sul std::future :

http://en.cppreference.com/w/cpp/thread/future/wait_for