[C/C++]建议在异步调用的函数的Callback中预留UserData参数

本文探讨了在C++中进行异步调用时,为何应当在Callback函数中预留UserData参数,以避免多线程环境下可能出现的错误。通过示例代码展示了如何使用UserData解决静态成员变量共享导致的问题,从而确保异步操作的线程安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有时候会碰到一些的C++程序员定义的异步函数(通过Callback通知)没有UserData参数,这样会给OO设计带来很大的麻烦。举个例子(只是例子,不讨论有没有必要作成异步函数):

 

 

typedef void (*PFCALLBACK)();

 

DWORD WorkingFunc(LPVOID* param)

{

 

    // Do something...

 

    PFCALLBACK pFun = (PFCALLBACK)param;

    pFun ();
    return 0;

}

 

 void Asynchronous(PFCALLBACK pCallbak)

{

    HANDLE hThrd = CreateThread(NULL, 0, WorkingFunc, pCallbak, 0, NULL);

    CloseHandle(hThrd );

}

 

 

如果要调用Asynchronous这个函数,通常可以这么做:

 

class myClass

{

public:

    static void myCallback();

    void myFunction();

private:

    static HANDLE m_hEvent;

};

 

HANDLE myClass::m_hEvent= NULL:

 

void myClass::myCallback()

{

    SetEvent(m_hEvent);

}

 

void myClass::myFunction()

{

     m_hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);

    Asynchronous(myCallback);

    // Do some thing

    WaitForSingleObject(m_hEvent, INFINITE);

    CloseHandle(m_hEvent);

    m_hEvent = NULL;

}

 

由于m_hEvent是静态成员变量,所有的类的对象都共用一个m_hEvent,所以当这些对象在不同线程中被调用时就可能造成错误!

 

 

所以,我们在设计使用Callback的异步函数时,应该预留UserData参数,这样,代码变成以下方式:

 

typedef void (*PFCALLBACK)(void* UserData);

struct ThreadParam

{

    PFCALLBACK pCallback;

    void* UserData;

};

 

DWORD WorkingFunc(LPVOID param)

{

 

    // Do something...

 

    ThreadParam* pParam = (ThreadParam*)param;

    pParam->pCallback(pParam->UserData);

    delete pParam;
    return 0;

}

 

 void Asynchronous(PFCALLBACK pCallbak, void* UserData)

{

    ThreadParam *pParam = new ThreadParam;

    pParam ->pCallback = pCallbak;

    pParam ->UserData = UserData;

    HANDLE hThrd = CreateThread(NULL, 0, WorkingFunc, pParam , 0, NULL);

    CloseHandle(hThrd);

}

 

而myClass可以实现成:

class myClass

{

public:

    static void myCallback(void* UserData);

    void myFunction();

};

 

void myClass::myCallback(void* UserData)

{

    HANDLE hHandle = (HANDLE)UserData

    SetEvent(hHandle);

}

 

void myClass::myFunction()

{

    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    Asynchronous(myCallback, hEvent);

    // Do some thing

    WaitForSingleObject(hEvent, INFINITE);

    CloseHandle(hEvent);

}

 

由于去掉了静态成员变量,所以在多线程的环境下也能保证正确工作。

大家可以去参考微软的Callback的设计,几乎都留了UserData或者类似的参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值