2013-06-03 11 views
7

ho imparato ad amare lambda, e qualche tempo fa ho scritto un semplice involucro che prende un lambda e inizia su un nuovo thread.Tracing punti creazione dei thread per il debug

// 
// Starts a task on a separate thread, when passed a lambda expression 
// 
template<typename T> 
smart_ptrs::w32handle StartTask(T f) 
{ 
    // Make a copy of the task on the heap 
    T* pTask = new T(f); 

    // Create a new thread to service the task 
    smart_ptrs::w32handle hThread(::CreateThread(
     NULL, 
     0, 
     (LPTHREAD_START_ROUTINE)& detail::start_task_proc<T>, 
     (LPVOID) pTask, 
     NULL, 
     NULL)); 

    // If the caller ignores this rc, the thread handle will simply close and the 
    // thread will continue in fire-and-forget fashion. 
    return hThread; 
} 

NOTA: Sì, lo so questo non ha veramente bisogno di un modello e potrebbe tranquillamente usare std::function. L'ho postato in questo modo perché corrisponde a versioni più complicate (coda asincrona) che ho bisogno di essere template.

Il risultato finale è una funzione che è molto facile da utilizzare algoritmi paralleli ecc Tuttavia si verifica un problema se si inizia ad utilizzare tale funzione estesamente. Poiché i thread creati sembrano provenire dalla stessa funzione piuttosto generica, può diventare difficile stabilire dove sono stati avviati nel codice. Di solito è possibile elaborare il contesto di ciò che stanno facendo, ma non è così semplice come in passato quando si utilizza una funzione di thread esplicita. Qualcuno ha un buon metodo per etichettare tali thread in modo che siano più facili da eseguire il debug?

+3

Se si utilizza lambda, ti sembra di avere il supporto C++ 11. Ma se lo hai, perché dovresti usare quella roba roba su WinAPI invece di 'std :: thread' di C++ 11? –

+0

Non risponde alla domanda in sé, ma conosci ['std :: async'] (http://en.cppreference.com/w/cpp/thread/async)? – Angew

+0

OT: Usare la deduzione argomento template su std :: function è più flessibile in tutto e potenzialmente più efficiente (non applicabile qui, scommetto). – sehe

risposta

3

Per quanto ne so dal codice, avrete thread che hanno uno start_task_proc da qualche parte nel loro callstack che chiama il loro oggetto funzione. È possibile modificare tale funzione per portare un puntatore a una struttura "Informazioni sull'attività", piuttosto che all'oggetto funzione nuda. Puoi inserire qualsiasi informazione che ti piace in quell'oggetto dell'informazione, ad es. numeri di riga e nomi di file di cui è stato creato il compito:

template <class T> 
struct TaksInfo { 
    T func; 
    unsigned line; 
    char const* file; 

    TaskInfo(T&& t, unsigned l, char const* f) 
    : func(std::move(t), line(l), file(f) {} 
}; 


template<typename T> 
smart_ptrs::w32handle StartTask(T f, unsigned line, char const* file) 
{ 
    // Make a copy of the task on the heap 
    auto pTask = new TaskInfo<T>(f, line, file); 

    // Create a new thread to service the task 
    smart_ptrs::w32handle hThread(::CreateThread(
     NULL, 
     0, 
     (LPTHREAD_START_ROUTINE)& detail::start_task_proc<T>, 
     (LPVOID) pTask, 
     NULL, 
     NULL)); 

    // If the caller ignores this rc, the thread handle will simply close and the 
    // thread will continue in fire-and-forget fashion. 
    return hThread; 
} 

#define START_TASK(f) StartTask(f, __LINE__, __FILE__) 

template <class T> 
DWORD start_task_proc(LPVOID lpParameter) { 
    auto pTask = (TaskInfo<T>*) lpParameter; 
    return pTask->func(); 
} 


//use: 
int main() { 
    auto threadHandle = START_TASK(([]() -> DWORD { std::cout << "foo\n"; return 42;})); 
} 

Se ora ispezionare pTask in start_task_proc è possibile vedere file e line Quale può dirti dove è stato avviato il compito.
Naturalmente si potrebbe evitare la struttura TaskInfo e rendere le informazioni appena un parametro di modello di start_task_proc:

template <class T, unsigned Line, char const* File> 
DWORD start_task_proc(LPVOID lpParameter) { /* as you have it */) 

template<unsigned Line, char const* File, typename T> //use T last fur type deduction 
smart_ptrs::w32handle StartTask(T f) 
{ 
    // Make a copy of the task on the heap 
    auto pTask = new T(std::move(f)); 

    // Create a new thread to service the task 
    smart_ptrs::w32handle hThread(::CreateThread(
     NULL, 
     0, 
     (LPTHREAD_START_ROUTINE)& detail::start_task_proc<T, Line, File>, //!!! 
     (LPVOID) pTask, 
     NULL, 
     NULL)); 

    // If the caller ignores this rc, the thread handle will simply close and the 
    // thread will continue in fire-and-forget fashion. 
    return hThread; 
} 

#define START_TASK(f) StartTask<__LINE__, __FILE__>(f) 
+0

+1, soluzione molto elegante. –

+0

Mi piace anche questo, relativamente poco overhead. – Benj

Problemi correlati