异步回调,生存期的问题

Lonely_Snow 2013-03-26 05:00:37
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
GMXX* gm = (GMXX*)lpParameter;

if (WaitForSingleObject(gm->m_readovp.hEvent, MAX_TIMEOUT) == WAIT_OBJECT_0)
{
ResetEvent(gm->m_readovp.hEvent);
if (gm->m_callback)
{
gm->m_callback->ReadCallback(gm->m_data, _tcslen(gm->m_data));
}
}
else
{
CancelIoEx(gm->m_hDevice, NULL);
}

return 0;
}

在上面的代码中,如果gm已经析构了,那么引用它的成员的时候,程序就会crash,请教各位大虾,遇到这样的问题,如何处理?我尝试过RegisterWaitForSingleObject,UnregisterWaitEx,但不清楚UnregisterWaitEx应该在什么时候去调,msdn上说,必须调用UnregisterWaitEx,并且不能在调用RegisterWaitForSingleObject注册的回调中调用。
...全文
217 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
zgl7903 2013-03-27
  • 打赏
  • 举报
回复
可以用两个事件,其中一个为线程退出事件,在解析传入的参数前,先置退出事件,保证线程在掌控之中 类似

DWORD DemoThread(LPARAM lParam)
{  
  THREADINFO *pInfo = (THREADINFO *)lParam;
  HANDLE hEvent2[] = 
  {
    pInfo->hExitEvnt, //退出事件。 CreateEvent时用manual-reset方式
    pInfo->hDoEvnt  //做事事件。CreateEvent时用auto-reset方式
  };

  BOOL bExitFlag = FALSE;//线程退出标志
  while(!bExitFlag)
  {
    switch(WaitForMultipleObjects(2, hEvent2, FALSE, tmOutTick))
    {
    case(WAIT_OBJECT_0 + 0)://退出事件
      {
        //清理退出 
        bExitFlag = TRUE;
        break;
      }
    case(WAIT_OBJECT_0 + 1)://做事事件
      {
        //……
        break;
      }
    case(WAIT_TIMEOUT)://超时
      {
        //处理超时……
        break;
      }
    default://不期望的事件
      {
        _ASSERT(FALSE);
        bExitFlag = -1;
        break;
      }
    }
  }
  return bExitFlag;
}

无言猪 2013-03-27
  • 打赏
  • 举报
回复
就没看懂你这个问题,是ThreadProc这个线程起来后,gm已经被析构,导致对gm->XX的访问引起crash.还是说你的gm->m_callback->ReadCallback(gm->m_data, _tcslen(gm->m_data),送出去的gm->m_data被上层保存起来,然后在使用时由于gm->m_data被free掉后引起crash.
阿麦 2013-03-27
  • 打赏
  • 举报
回复
我是这么做的(VC): 调用 CMyClass x CMyClass *px = new CMyClass() *px = x; HANDLE h = (HANDLE)_beginthreadex(NULL, 0, Proc, px, 0, NULL); ...... 回调 unsigned CALLBACK Proc(void *e) { CMyclass *p = (CMyClass *)e; ...... delete p; }
oyljerry 2013-03-26
  • 打赏
  • 举报
回复
引用 4 楼 Lonely_Snow 的回复:
引用 3 楼 oyljerry 的回复:需要用new的方式分配gm->m_data在堆上,然后ReadCallback()里面使用完了以后调一个释放函数来释放gm->m_data 但关键我做的是底层的设计,你不能依赖上层怎么用
那就用share_ptr。
菜牛 2013-03-26
  • 打赏
  • 举报
回复
如果你没法控制调用方,什么同步都没用。用try/catch处理异常吧。
zcchm 2013-03-26
  • 打赏
  • 举报
回复
试试boost的shared_ptr & weak_ptr
Red_angelX 2013-03-26
  • 打赏
  • 举报
回复
传个结构体 把new和delete的函数指针放进去
Lonely_Snow 2013-03-26
  • 打赏
  • 举报
回复
引用 3 楼 oyljerry 的回复:
需要用new的方式分配gm->m_data在堆上,然后ReadCallback()里面使用完了以后调一个释放函数来释放gm->m_data
但关键我做的是底层的设计,你不能依赖上层怎么用
oyljerry 2013-03-26
  • 打赏
  • 举报
回复
需要用new的方式分配gm->m_data在堆上,然后ReadCallback()里面使用完了以后调一个释放函数来释放gm->m_data
孤客天涯 2013-03-26
  • 打赏
  • 举报
回复
既然是异步回调,肯定会有问题 把参数new一份副本转过去,这样异步回调函数中就与gm指针无关了 m_data = new XXX; m_data = gm->m_data;(伪代码,意为拷贝一个副本) gm->m_callback->ReadCallback(m_data, _tcslen(m_data));
无言猪 2013-03-26
  • 打赏
  • 举报
回复
整个逻辑都是在你的控制下啊,你知道gm什么时候会析构,在析构后判断一个标志不去调用gm->系列的函数.

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧