2013-08-21 28 views
5

Chỉ cần thử nghiệm, nhưng tôi đã tự hỏi nếu nó có thể làm cho công việc này mã (như trong biên dịch):Sử dụng CreateThread với một 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(); 
} 

Tôi có nghi ngờ cằn nhằn này vì chữ ký tiêu chuẩn cho một callback LPTHREAD_START_ROUTINEDWORD WINAPI Callback(PVOID) Tôi sẽ không thể thực hiện việc này để biên dịch mà không cần thêm thẻ WINAPI (nhưng theo ngữ pháp bất hợp pháp). Nói đến điều gì, các thuộc tính WINAPICALLBACK (cho biết WndProc) là gì? Tôi chưa bao giờ thực sự hiểu tại sao trong một số trường hợp bạn có thể có nhiều thuộc tính trên một hàm.

+0

'main' là bắt buộc để có' int' làm kiểu trả lại. Bạn cũng cần một lambda '__stdcall', điều này là không thể. Bạn có thể bọc nó để có một lambda (hoặc bất cứ điều gì), mặc dù, hoặc chỉ sử dụng ''. – chris

+7

Vì bạn rõ ràng đang sử dụng C++ 11, tại sao không chỉ sử dụng 'std :: thread' mà là di động và tích hợp tốt với lambdas, thay vì nền tảng cụ thể' CreateThread'? – syam

+0

Tôi chỉ mới bắt đầu học. Nhưng tôi sẽ xem xét điều đó. Cảm ơn! – sircodesalot

Trả lời

11

Thực tế điều này là có thể với Visual C++ 2012 trở lên; để báo giá từ Microsoft's list of C++ feature support:

Ngoài ra trong Visual C++ trong Visual Studio 2012, stateless lambdas có thể chuyển đổi thành con trỏ hàm. ... chúng tôi đã thực hiện lambdas có thể chuyển đổi thành con trỏ hàm có yêu cầu tùy ý các quy ước . Đây là quan trọng khi bạn đang sử dụng API mong đợi những thứ như __stdcall con trỏ hàm

Vì vậy, trong Visual C++ 2012 bạn có thể làm một cái gì đó như:

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

Điều này có nghĩa bạn cũng có thể sử dụng lambdas với API khác chức năng mong đợi các hàm gọi lại (ví dụ như EnumWindows()CreateDialogParam()).

+2

Ah hah! Tôi từ lâu tự hỏi làm thế nào điều này sẽ làm việc xem xét các ABI x86 đòi hỏi '__stdcall' cho (nhất) của các điểm vào thread của nó (x64 không thực sự quan trọng). Cảm ơn bạn đã chỉ ra điều này, ** + 1 ** –

2

Bạn có thể làm cho mọi việc một chút ít dài dòng sử dụng 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); 

Hoặc, đối với người nghiện ma copy dán người tìm thấy câu trả lời này sau này;), đây là tất cả các bạn cần:

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

trình biên dịch cho biết tôi không thể truyền một lambda vào LPTHREAD_START_ROUTINE – J3STER

0

ít nhất trong hiện tại * phiên bản của Mingw64 bạn có thể chỉ định các quy ước gọi của một hàm lambda, như trong []() WINAPI {}:

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

*) Đã thử nghiệm với i686-w64-mingw32-g ++ - win32 (GCC) 6.3.0 20170516. Phiên bản cũ hơn cũng có thể hoạt động.

Các vấn đề liên quan