【问题标题】:Function pointers in C++C++中的函数指针
【发布时间】:2016-06-23 14:48:15
【问题描述】:

我用CreateThread function用C++写了一个类似C# BackgroundWorker的类。我的代码:

BackgroundWorker.h:

class BackgroundWorker
{
    private :
        HANDLE _threadHandle;
        unsigned int _threadCallcounter;
        DWORD _threadID;
    public:
        BackgroundWorker();
        ~BackgroundWorker();
        virtual DWORD WINAPI Function(LPVOID vpPram);
}

BackgroundWorker.cpp:

#include "BackgroundWorker.h"
void BackgroundWorker::DoWork()
{
    this->_threadHandle = CreateThread(NULL,
        0,this->Function,&this->_threadCallcounter,
        0, &this->_threadID); // !!!***This part throws an error***!!!
}

然后我创建了另一个派生自 BackgroundWorker 的类:

ListenThread.cpp:

class ListenThread :public BackgroundWorker
{
    DWORD WINAPI Function(LPVOID vpPram)
    {
        //DO somthing...
        return 0;
    }
};

但是那行给了我以下错误:

非标准语法;使用 '&' 创建指向成员的指针

【问题讨论】:

  • this->Function 是什么意思?调用它?传递函数的地址?
  • 但你知道std::thread,对吧?
  • 放弃 CreateThread(在 C++ 代码中不应该使用它,15 年前到处都提到过它),并切换到 std::thread。
  • @SergeyA:如果std::thread 确实提供了与CreateThread(或_beginthreadex)相同的功能,那么您说得有道理。事实是,它没有。例如,尝试使用std::thread 创建一个处于挂起状态的线程。
  • @IInspectable,首先,CreateThread 应该永远在 C++ 代码中使用。这一点是确定的,我希望,没有争议。至于使用std::thread_beginthreadex,我没有看到OP 使用后者的任何额外功能。很明显,原生线程的一些特性是没有通过std::thread暴露出来的,但是除非用到,否则std::thread应该是首选。

标签: c# c++ multithreading backgroundworker createthread


【解决方案1】:

CreateThread 期望的函数指针必须有这个签名:

DWORD WINAPI ThreadProc(LPVOID lpParameter);

当你创建一个成员函数时,它会得到一个不可见的“this”参数作为第一个参数,所以你隐含地声明了这样的东西:

DWORD WINAPI ThreadProc(BackgroundWorker *this, LPVOID lpParameter);

创建一个静态成员函数以省略 this 指针,如果您在线程例程中需要该指针,请将其作为 void * 参数传递

【讨论】:

    【解决方案2】:

    您的错误消息意味着您需要将指针传递给&Function,而不是DoWork 中的Function

    很遗憾,修复此问题无济于事。 CreateThread 不适用于(非静态)成员函数。一种解决方案是创建一个静态方法来用作实际的线程启动函数。

    检查这个例子:

    #include <Windows.h>
    #include <iostream>
    
    class BackgroundWorker
    {
    private :
        HANDLE _threadHandle;
        DWORD _threadID;
    
    public:
        static DWORD WINAPI StaticThreadStart(void * Param) {
            BackgroundWorker * This = static_cast<BackgroundWorker *>(Param);
            return This->Function();
        }
    
        virtual DWORD Function() {
            return 0;
        }
    
        void DoWork() {
            _threadHandle = CreateThread(NULL, 0, StaticThreadStart, this, 0, &_threadID);
        }
    };
    
    class ListenThread : public BackgroundWorker {
        DWORD Function() override {
            std::cout << "Working...\n";
            return 0;
        }
    };
    
    int main()
    {
        ListenThread cl;
        cl.DoWork();
    
        // Call pause to wait for new thread in this example
        system("pause");
        return 0;
    }
    

    【讨论】:

    • 您不应该将CreateThread 用于使用 CRT(您是)的线程。这是documented“调用 C 运行时库 (CRT) 的可执行文件中的线程应使用 _beginthreadex 和 _endthreadex 函数进行线程管理,而不是 CreateThread 和 ExitThread;[...]。如果使用 CreateThread 创建的线程调用 CRT,CRT 可能会在内存不足的情况下终止进程。"
    猜你喜欢
    • 1970-01-01
    • 2010-11-19
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    相关资源
    最近更新 更多