Abstract Base类C ++中的静态回调

时间:2013-04-04 10:00:52

标签: c++ oop templates callback c++builder

我遇到了一个我遇到的OOP /设计问题,我非常希望有人可以引导我走向不需要完全重写的方向。

系统是Windows服务必不可少的,它有~9个辅助线程负责特定任务。所有线程共享一些共同的功能(例如,在内部发送和接收消息的能力等)。因此,我定义了一个抽象基类,所有线程都从该基类继承。

但是,其中四个线程也使用基于第三方IPC系统的进程间通信系统(madshi的CreateIpcQueue)。为了在这四个线程中保存复制所有相同的代码,我定义了一个额外的类来支持这个:

TThread <-TBaseThread<-TIPCBaseThread<- Four IPC threads
               ^- All other threads.

IPC系统的机制是你定义一个Callback函数,然后调用CreateIpcQueue传递它这个Callback。在我的TIPCBaseThread中,我松散地做了这样的事情:

// TIPCBaseThread.h
class TIPCBaseThread : public TBaseThread
{
 private:
   static TIPCBaseThrd *pThis; 
   // defines the callback to use with the IPC queue 
   static void CALLBACK IPCQueue(char *cName, void *pMsgBuf, unsigned int iMsgLen, 
                                 void *pRtnBuf, unsigned int iRtnLen);
 protected:
   // virtual method, to be defined in derived classes, to handle IPC message
   virtual void ProcessIPCMsg(char *cName, void *pMsgBuf, unsigned int iMsgLen, void *pRtnBuf, 
                              unsigned int iRtnLen) = 0;
 public:
   CRITICAL_SECTION csIPCCritSect;
 …

// TIPCBaseThread.cpp
TIPCBaseThrd* TIPCBaseThrd::pThis = 0;

__fastcall TIPCBaseThread::TIPCBaseThread(…) : TBaseThread(…)
{
  pThis = this;
  InitializeCriticalSectionAndSpinCount(&csIPCCritSect, 1000);
  CreateIpcQueueEx(“SomeQueueName”, IPCQueue, 1, 0x1000);
                                     //^Callback Queue
  …
}

void CALLBACK TIPCBaseThread::IPCQueue(char *cName, void *pMsgBuf, unsigned int iMsgLen, 
                                       void *pRtnBuf, unsigned int iRtnLen)
{
  EnterCriticalSection(&pThis->csIPCCritSect);
  pThis->ProcessIPCMsg(cName, pMsgBuf, iMsgLen, pRtnBuf, iRtnLen);
  LeaveCriticalSection(&pThis->csIPCCritSect);
}

我的一般想法是TIPCBaseThread将有效地负责创建和管理IPC通道,然后在各种派生类中调用ProcessIPCMsg()。

现在,当我测试系统并向任何IPC通道发送消息时,消息在TIPCBaseThread回调中被接收,但被传递到最后一个派生类(要创建),而不是应该接收的类它。我假设它与

有关
[static TIPCBaseThrd *pThis] 
当实例化每个派生类时,

属性被覆盖(但我承认我不是100%肯定)?

有人能引导我朝着正确的方向前进吗?显然我想确切地知道是什么导致了这个问题,但理想情况下我想知道是否有一个解决方法可以避免必须完全重写整个对象的继承 - 显然还有更多内容在引擎盖下进行我已经表现出来,如果我不得不完全抛弃这个设计,我将会遇到严重的问题。

非常感谢,

迈克柯林斯

2 个答案:

答案 0 :(得分:1)

我认为您应该更改回调以将实例作为参数

static void CALLBACK IPCQueue(TIPCBaseThread *instance, 
                              char *cName, void *pMsgBuf, unsigned int iMsgLen, 
                              void *pRtnBuf, unsigned int iRtnLen);

...

void CALLBACK TIPCBaseThread::IPCQueue(char *cName, void *pMsgBuf, unsigned int iMsgLen, 
                                       void *pRtnBuf, unsigned int iRtnLen)

{
  ...
  instance->ProcessIPCMsg(cName, pMsgBuf, iMsgLen, pRtnBuf, iRtnLen);
  ...
}

答案 1 :(得分:0)

有一个非常奇怪的事情:pThis = this; static TIPCBaseThrd *pThis;

这意味着在任何时间点只有TIPCBaseThrd的最新实例可以通过pThis访问(之前的所有实例都已被覆盖);当然还有一个问题是这个全局值不受任何同步保护(互斥,原子,......)

这很不幸,但这个static TIPCBaseThrd *pThis;只是一个不可能有效的可怕想法。