c++抽象基类中的静态回调



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

系统本质上是一个Windows服务,它有大约9个次要线程负责特定的任务。所有线程共享一些公共功能(例如,能够在内部发送和接收消息等)。因此,我定义了一个抽象基类,所有线程都从它继承。

然而,其中四个线程也使用基于第三方IPC系统(madshi的CreateIpcQueue)的进程间通信系统。为了避免在这四个线程中复制所有相同的代码,我定义了一个额外的类来支持这一点:
TThread <-TBaseThread<-TIPCBaseThread<- Four IPC threads
               ^- All other threads.
IPC系统的机制是你定义一个回调函数,然后调用CreateIpcQueue传递给它这个回调。在我的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%确定)?

谁能给我指个方向吗?显然,我想知道到底是什么导致了这个问题,但理想情况下,我想知道是否有一种方法可以避免完全重写整个对象继承——显然,在引子下面有比我所展示的更多的东西,如果我不得不完全放弃这个设计,我将会遇到严重的问题。

提前感谢,

麦克科林斯

我认为你应该改变回调,以实例作为参数

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);
  ...
}

有一件很奇怪的事:pThis = this;static TIPCBaseThrd *pThis;

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

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

最新更新