2013-08-21 20 views
5

Proprio la sperimentazione, ma mi chiedevo se è possibile fare questo lavoro di codice (come in compilazione):Utilizzare CreateThread con un lambda

void main() { 
    int number = 5; 

    DWORD(*dontThreadOnMe)(PVOID) = [](PVOID data) { 
     int value = *(int*) data; 

     cout << value << endl; 
     cout << "This callback executed successsfully" << endl; 
    }; 

    CreateThread(NULL, NULL, dontThreadOnMe, &number, NULL, NULL); 
    cin.get(); 
} 

ho questo sospetto che perché la firma standard per un LPTHREAD_START_ROUTINE callback è DWORD WINAPI Callback(PVOID) Non riuscirò a farlo compilare senza il tag aggiunto (ma grammaticamente illegale) WINAPI. A proposito, quali sono esattamente gli attributi WINAPI e CALLBACK (per esempio WndProc)? Non ho mai veramente capito il motivo per cui in determinate circostanze potresti avere più attributi su una funzione.

+0

'main' è necessario avere' int' come tipo di ritorno. Dovresti anche avere un lambda '__stdcall', che non è possibile. Puoi avvolgerlo per fare un lambda (o qualsiasi altra cosa), comunque, o semplicemente usare ''. – chris

+7

Dato che ovviamente stai usando C++ 11, perché non usare semplicemente 'std :: thread' che è portatile e si integra bene con lambdas, invece del' CreateThread 'specifico della piattaforma? – syam

+0

Ho appena iniziato a studiare. Ma esaminerò quello. Grazie! – sircodesalot

risposta

11

In realtà questo è possibile con Visual C++ 2012 e versioni successive; di citare Microsoft's list of C++ feature support:

Inoltre in Visual C++ in Visual Studio 2012, lambda apolidi sono convertibili a funzionare puntatori. ... abbiamo reso stateless lambda convertibili a puntatori di funzioni che hanno convenzioni arbitrarie chiamate . Questo è importante quando si utilizza le API che si aspettano cose come __stdcall puntatori a funzione

Così in Visual C++ 2012 si può fare qualcosa di simile:

unsigned int id; 
HANDLE hThread = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, 
    [](void* pData) -> unsigned int { 
     // I'm a thread! 
     return 0; 
    }, pThreadData, 0, &id)); 

Ciò significa che si può anche utilizzare lambda con altri API funzioni che prevedono funzioni di callback (ad esempio EnumWindows() e CreateDialogParam(), ad esempio).

+2

Ah ah! Mi sono chiesto a lungo come funzionerebbe, considerando che l'ABI x86 richiede '__stdcall' per (la maggior parte) dei suoi punti di immissione del thread (x64 non ha molta importanza). Grazie per aver segnalato questo, ** + 1 ** –

2

È possibile rendere le cose un po 'meno prolisso utilizzando auto :)

auto dontThreadOnMe = [](LPVOID data) -> DWORD { 
    int value = *(int*)data; 
    std::cout << value << std::endl; 
    std::cout << "This callback executed successsfully" << std::endl; 
    return 0; //don't forget your return code! 
}; 

int number = 42; 
auto thread = CreateThread(nullptr, 0, dontThreadOnMe, &number, 0, nullptr); 

Oppure, per i tossicodipendenti copia incolla che trovano questa risposta più tardi;), questo è tutto ciò che serve:

auto work = [](LPVOID data) -> DWORD { return 0; }; 
int thread_param = 42; 
auto thread = CreateThread(nullptr, 0, work, &thread_param, 0, nullptr); 
+0

il compilatore dice che non posso lanciare un lambda in un LPTHREAD_START_ROUTINE – J3STER

0

almeno in corso * versioni di Mingw64 è possibile specificare la convenzione di chiamata di una funzione lambda, come in []() WINAPI {}:

CreateThread(
    nullptr, // lpThreadAttributes 
    0,  // dwStackSize 
    [](void *param) WINAPI -> DWORD { // lpStartAddress 
     (void) param; 
     return 0; 
    }, 
    nullptr, // lpParameter 
    0,  // dwCreationFlags 
    nullptr // lpThreadId 
); 

*) Testato con i686-w64-mingw32-g ++ - win32 (GCC) 6.3.0 20170516. Anche la versione precedente potrebbe funzionare.

Problemi correlati