使用私有成员函数调用 Win32 QueueUserWorkItem()

Posted

技术标签:

【中文标题】使用私有成员函数调用 Win32 QueueUserWorkItem()【英文标题】:Calling Win32 QueueUserWorkItem() with a private member function 【发布时间】:2016-08-06 16:45:13 【问题描述】:

我正在尝试使用 Win32 函数 QueueUserWorkItem() 将私有成员函数(不应作为公共或受保护的)调用为工作项。我知道我以前做过,而且很容易,但现在我找不到那个 sn-p,也不能让 bind() voodoo 工作。因此,就这个问题而言,该类是:

class Arbitrary 

    public:
        Arbitrary() ;
        ~Arbitrary() ;

        bool    UsefulPublicFunction(unsigned uParameter) ;

    protected:

    private:
        void    PrivateWorkItem(void* pVoid) ;
 ;

UsefulPublicFunction() 内部,我们可能会看到:

LPTHREAD_START_ROUTINE pThreadStartRoutine ;
ULONG uFlags = 0 ;
void* pContext = nullptr ;

if (QueueUserWorkItem(pThreadStartRoutine, pContext, uFlags)) 
    //blah blah blah

我似乎在杂草丛生的地方是分配给pThreadStartRoutine,例如:

pThreadStartRoutine = std::bind<&Arbitrary::PrivateWorkItem, this, std::placeholders::_1> ;

我知道PrivateWorkItem 的签名可能应该更改为:

private:
    DWORD   WINAPI  PrivateWorkItem(void* pVoid) ;

即使有了这样的改变,也没有喜悦。 VS2015 真的很讨厌我使用bind() 的方式。

我对@9​​87654331@ 的分配应该是什么样的?

【问题讨论】:

了解您看到的错误会很有帮助。 请求了错误消息......对我来说它没用 - 也许对你来说很有意义:“没有重载函数的实例“std::bind”与所需的类型匹配” 【参考方案1】:

这似乎有效:

#include <Windows.h>

#include <stdio.h>

#include <functional>

using namespace std::placeholders;

class Arbitrary 

    public:

        bool UsefulPublicFunction(int uParameter);

    protected:

    private:
        typedef std::function<void (void)> CallbackType;
        static DWORD WINAPI ProcessWorkItem(void* pVoid);
        void PrivateWorkItem1(int arg1, int arg2);
        void PrivateWorkItem2(char * arg1);
;

void Arbitrary::PrivateWorkItem1(int arg1, int arg2)

    printf("Numbers are %u %u\n", arg1, arg2);
    return;


void Arbitrary::PrivateWorkItem2(char * arg1)

    printf("String is %s\n", arg1);
    return;


DWORD WINAPI Arbitrary::ProcessWorkItem(void* pVoid)

    CallbackType * callback = static_cast<CallbackType *>(pVoid);
    (*callback)();
    delete callback;
    return 0;


bool Arbitrary::UsefulPublicFunction(int param1)

    QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem1, this, param1, 7)), 0);

    QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem2, this, (char *)"This is my string")), 0);

    Sleep(1000);
    return true;


int main(int argc, char ** argv)

    Arbitrary x;

    x.UsefulPublicFunction(5);

    return 0;

【讨论】:

对不起,我还没有足够的分数来提高“分数”哈利。【参考方案2】:

试试类似的方法:

class Arbitrary 

    public:
        Arbitrary() ;
        ~Arbitrary() ;

        bool UsefulPublicFunction(unsigned uParameter);

    protected:

    private:
        static DWORD WINAPI PrivateWorkItem(void* pVoid) ;
        void PrivateFunction();
 ;

DWORD WINAPI Arbitrary::PrivateWorkItem(void* pVoid)

    static_cast<Arbitrary*>(pVoid)->PrivateFunction();
    return 0;


...

if (QueueUserWorkItem(&PrivateWorkItem, this, 0)) 
    //blah blah blah

【讨论】:

“感觉”相当笨重,对我来说,从长期代码维护的角度来看似乎并不可靠——主要是因为类中实际上有许多独特的私有工作者函数。但是,是的,我已经按照您建议的方式完成了它,并且我还使用正确的签名声明了自动变量,然后使用 memcpy 将其猛烈撞击到 pThreadStartRoutine 中,但这对我来说似乎同样笨拙。就这一点而言,当实习生在 10 年内维护此代码时,使用 bind 似乎很简单。 您不能真正使用std::bind() 来设置Win32 API 回调函数(请参阅***.com/questions/18161680)。我上面展示的是不涉及丑陋黑客的“最干净”的解决方案。 您大概可以使用一个静态函数,该函数接受指向由 std::bind 生成的转发调用包装器的指针。只要对包装器的调用来自 C++ 而不是 Windows。 感谢 Remy 和 Harry 的快速回复。 回到最初的问题,我想澄清一下。 PrivateWorkItem (pVoid) 的参数已经被提及,因此我们不能将其重新用于其他用途,例如类指针。我对这个问题思考得越多,它看起来就越复杂,所以我确信我遗漏了一些明显的东西。想象一下 Arbitrary 类有 30 个私有工作项 - 你将如何解决这个问题?

以上是关于使用私有成员函数调用 Win32 QueueUserWorkItem()的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中调用私有方法

私有(private)成员

特殊作用的私有成员函数

如何使用 gmock 模拟修改 C++ 类中的私有变量的成员函数?

OVERLAPPED Win32 结构中的 hEvent 成员

c++ - 使用私有参数调用公共函数