【问题标题】:Creating thread with _beginthreadex, __stdcall and a lambda使用 _beginthreadex、__stdcall 和 lambda 创建线程
【发布时间】:2019-07-25 11:17:36
【问题描述】:

我正在使用带有 mingw 的 CodeBlocks,gcc 版本 5.1.0。

我的代码如下所示:

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

然后在其他函数的其他地方:

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

代码运行良好。今天学习了 lambda 表达式,想尝试一下。

所以我删除了函数doWork() 并尝试对:

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);

但我得到错误:

||=== 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)) ===|

我想我必须把 __stdcall 放在某个地方。我还没有通过谷歌搜索找到任何东西。

【问题讨论】:

  • 既然你有 lambda,我建议你也学习一下 std::thread 类。
  • @Someprogrammerdude 谢谢,但我必须使用 _beginthreadex。
  • 不,你没有:)

标签: c++ multithreading lambda mingw


【解决方案1】:

这实际上几乎按原样工作。没有捕获的 Lambda 可以转换为函数指针,因此它们在一定程度上与类 C 的 API 兼容。

但是,_beginthreadex 需要一个指向 __stdcall 函数的函数指针; “本机”函数指针是这个;转换后的 lambda 不是。

但是微软好心让it can be!您所需要的只是强制转换函数指针。这有点不直观,因为您的 lambda 已经是 __stdcall (that's what WINAPI expands to),但无论如何。

所以:

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
);

但实际上我推荐std::thread 来代替干净、可移植的代码!

【讨论】:

  • 谢谢。我查找了 std::thread ,但它看起来对我来说不是一个好选择,因为我需要检查线程是否完成(现在我使用 WaitForSingleObject())以及线程函数返回的内容(GetExitCodeThread())。我知道期货是一种选择,但对于已经有效的东西来说,这似乎是额外的工作。
  • 你的意思是像myThread.join()? (返回值比较棘手)老实说,即使您必须跳过一两个小圈,总体而言非常值得。
  • join() 等待线程完成(如果它仍在工作)。当它工作时,我在主线程中运行了进度条,我必须检查用户是否按下了进度条上的“取消”按钮。创建的线程 (napolniDrevo()) 根本无法完成,这意味着 join() 不会完成。这些只是我脑海中的一些问题。
  • 好的,那么同步进度指示器和可能的条件变量就是为此。您现在所做的一切都可以通过std::thread 完成。尽量避免使用不需要的特定于平台的 API。
  • 不错。玩得开心!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 2012-06-22
  • 2013-07-16
  • 1970-01-01
  • 2010-09-24
  • 2014-04-25
相关资源
最近更新 更多