【问题标题】:Call AfxBeginThread with class member function?用类成员函数调用 AfxBeginThread?
【发布时间】:2011-12-12 18:24:45
【问题描述】:

如何使用任意非静态类方法调用 AfxBeginThread?也许我可以用boost bind 做点什么?以下是 Microsoft 的预期用法(并且是调用非静态方法的示例,但它是硬编码的方法):

UINT MyThreadProc( LPVOID pParam )
{
    CMyObject* pObject = (CMyObject*)pParam;

    if (pObject == NULL ||
        !pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
    return 1;   // if pObject is not valid

    // do something with 'pObject'

    return 0;   // thread completed successfully
}

// inside a different function in the program
...
pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);

【问题讨论】:

  • 您已经有了解决方案。您在问题中发布了它。哪方面对你来说不够?
  • 我希望能够在线程中执行任意类成员函数,就像使用 boost 线程一样。我发布的示例有效,但它被硬编码为特定的类。我想使用 boost 线程,但在 MFC 上下文中使用它时似乎存在一些问题。
  • 你必须在有占位符注释的地方调用你的成员函数“用'pObject'做一些事情”。抱歉,事情就是这样。

标签: c++ windows multithreading boost-bind member-functions


【解决方案1】:

您的代码示例很好。对于要在单独的线程中调用的每个不同的非静态类方法,您都需要一个线程函数。

boost:bind 对您没有任何帮助... AfxBeginThread 必须是 C++ 模板函数,否则它不能与 boost::bind 或带有捕获的 C++11 lambda 兼容。

另一种方法是创建一个结构,为您将拥有的每个类/方法组合使用一个枚举,但这仍然需要您手动为每个类/方法组合的枚举和回调函数添加代码。然而,它的代码并不比为每个类/方法组合创建一个单独的线程函数少多少。

struct ThreadData
{
  LPVOID object;
  enum ObjectCallType {
    Foo_Foo,
    Foo_Bar
  } objectCallType;
  LPVOID* param;
  ThreadData( LPVOID pobject, ObjectCallType poct, LPVOID* pparam=0 )
  :object(pobject), objectCallType(poct), param(pparam) {}
};

UINT MyThreadProc( LPVOID pParam )
{
    TheadData* thData = (ThreadData*)pParam;
    try 
    {
        switch( thData->objectCallType )
        {
            case ThreadData::Foo_Foo:
                Foo* foo = (Foo*)thData->object;
                foo->foo();
                break;
            case ThreadData::Foo_Bar:
                Foo* foo = (Foo*)thData->object;
                foo->bar( thData->param );
                break;
            default:
                throw std::exception("unhandled method call type");
        }
    }
    catch( std::exception& e )
    {
        std::cerr << e.what() << std::endl;
        delete thData;
        return 1;
    }
    delete thData;
    return 0;
}



//usage:
AfxBeginThread(MyThreadProc, new ThreadData(myFooObject,ThreadData::Foo_Bar,myFooCallParam));

Boost 示例(未经测试):

boost::thread myFooFooThread( boost::bind( &Foo::Foo, myFooObject ) );

【讨论】:

  • 我没有使用 boost 绑定的经验。您能否将 boost 绑定对象作为参数传递给 MyThreadProc,然后让 MyThreadProc 简单地调用 boost 绑定函数?
  • @User:不,你不能,因为你必须将 boost::bind 对象从 LPVOID 转换为实际对象,这不是微不足道的,因为几乎每个 boost::bind 对象都有一个不同的(复杂的)类型。但是,您可以将 boost::bind 对象与 boost::thread 一起使用。
  • 鉴于我想知道您是否可以将 boost::bind 与 Mark Ransom 的回答中的模板化 StartThread 函数一起使用。
  • @User: 是的,你可以,但是你仍然需要指定绑定表达式的类型作为模板参数,这很麻烦,除非你可以使用 C++11 的特性@987654324 @ 和 decltypestd::function
【解决方案2】:

您需要一个静态函数来传递给 AfxBeginThread,但它可以是一个调用对象的非常简单的函数。这是一个可能有效的未经测试的模板函数。

template<class T>
UINT __cdecl StartThread(LPVOID pParam)
{
    return ((T*)pParam)->MyThreadProc();
}

【讨论】:

    【解决方案3】:

    我知道这个问题已经很老了——但它与我目前的情况很接近。我正在开发一个用 Visual Studio 2008 项目编写的应用程序,并希望避免所有启动功能。

    我发现 AfxBeginThread 有两种不同的调用方式:一种需要 start 函数(用于启动工作线程);另一个将派生自 CWinClass 的类作为其第一个参数,用于创建用户界面连接对象和工作线程。

    我选择第二个选项。这在上述问题中也不起作用吗?

    【讨论】:

      猜你喜欢
      • 2020-12-04
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      • 2021-09-02
      • 2020-10-11
      • 2011-04-02
      • 2016-10-18
      相关资源
      最近更新 更多