1

I'm using CodeBlocks with mingw, gcc version 5.1.0.

I have a code that looks like this:

unsigned int __stdcall doWork(void* data)
{
    if (napolniDrevo())
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

Then somewhere else in other function:

HANDLE m_hThread = (HANDLE)_beginthreadex(0, 0, &doWork, 0, 0, 0);

The code works fine. Today I learned about lambda expressions, and wanted to try it.

So I deleted function doWork() and tried to do the same with:

auto lambda = [](void* data) WINAPI -> unsigned int {if (napolniDrevo()) return 0; else return 1;};
HANDLE m_hThread = (HANDLE)_beginthreadex(0, 0, lambda, 0, 0, 0);

But I get error:

||=== Build: Release in CtrlData (compiler: GNU GCC Compiler) ===|
||warning: ./wx_pch.h.gch/Debug_wx_pch_h_gch: not used because `__WXDEBUG__' not defined [-Winvalid-pch]|
C:\Users\M0097932\Desktop\CtrlData\CtrlDataMain.cpp||In member function 'void DataGetterFrame::OnButton2Click(wxCommandEvent&)':|
C:\Users\M0097932\Desktop\CtrlData\CtrlDataMain.cpp|551|error: invalid user-defined conversion from 'DataGetterFrame::OnButton2Click(wxCommandEvent&)::<lambda(void*)>' to 'unsigned int (__attribute__((__stdcall__)) *)(void*)' [-fpermissive]|
C:\Users\M0097932\Desktop\CtrlData\CtrlDataMain.cpp|550|note: candidate is: DataGetterFrame::OnButton2Click(wxCommandEvent&)::<lambda(void*)>::operator unsigned int (*)(void*)() const <near match>|
C:\Users\M0097932\Desktop\CtrlData\CtrlDataMain.cpp|550|note:   no known conversion from 'unsigned int (*)(void*)' to 'unsigned int (__attribute__((__stdcall__)) *)(void*)'|
C:\Program Files (x86)\CodeBlocks\MinGW\include\process.h|100|note:   initializing argument 3 of 'long unsigned int _beginthreadex(void*, unsigned int, unsigned int (__attribute__((__stdcall__)) *)(void*), void*, unsigned int, unsigned int*)'|
||=== Build failed: 1 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|

I guess I have to put __stdcall somewhere. I didn't find anything by googling yet.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
user3007875
  • 123
  • 7

1 Answers1

3

This actually almost works as-is. Lambdas with no captures can convert to function pointers so they are, to a degree, compatible with C-like APIs.

However, _beginthreadex is expecting a function pointer to a __stdcall function; the "native" function pointer is this; the converted lambda is not.

But Microsoft have kindly made it so that it can be! All you need is a cast to "coerce" the function pointer. This is a little unintuitive because your lambda is already __stdcall (that's what WINAPI expands to), but whatever.

So:

auto lambda = [](void* data) WINAPI -> unsigned int
{
    return (napolniDrevo() ? 0 : 1);
};

HANDLE m_hThread = (HANDLE)_beginthreadex(
    0, 0,
    static_cast<unsigned int(WINAPI*)(void*)>(lambda),
    0, 0, 0
);

But actually I'd recommend std::thread instead for clean, portable code!

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Thank you. I looked up std::thread but it doesn't look like good option for me, because I need to check if thread is done (now I use WaitForSingleObject()) and what the thread function returns (GetExitCodeThread()). I know futures are an option, but it seems like extra work for what already works. – user3007875 Jul 25 '19 at 12:48
  • 1
    You mean like `myThread.join()`? (The return value is trickier) Honestly though even if you have to jump through one or two minor hoops, it's _well_ worth it overall. – Lightness Races in Orbit Jul 25 '19 at 13:00
  • join() waits for thread to finish if it's still working. While it is working, I have progress bar running in main thread, where I have to check if user pressed "cancel" button on the bar. Created thread (napolniDrevo()) could not finish at all, which means join() wouldn't finish. These are just some problems off the top of my head. – user3007875 Jul 25 '19 at 13:29
  • 1
    Okay, then synchronised progress indicators and possibly condition variables are for that. Everything you are doing now you can do with `std::thread`. Try to avoid platform-specific APIs where you don't need them. – Lightness Races in Orbit Jul 25 '19 at 13:46
  • Damn you are correct, I used c++ future and only needed async(), future.wait_for() and future.get(). Much cleaner code. Thanks! – user3007875 Jul 26 '19 at 06:46
  • 1
  • Hi,this code seems can not be compiled with latest vs2019. I tried it here https://godbolt.org/z/hsssnPEvq. –  blackshadow Jul 11 '21 at 14:15