1

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

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

但是,其中四个线程还使用了基于第 3 方 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% 确定)?

谁能在这里引导我朝着正确的方向前进?显然我想知道究竟是什么导致了这个问题,但理想情况下我想知道是否有一种解决方法可以避免完全重写整个对象继承——显然还有更多事情要做比我展示的要多,如果我必须完全放弃这个设计,我会遇到严重的问题。

提前谢谢了,

迈克·柯林斯

4

2 回答 2

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);
  ...
}
于 2013-04-04T10:28:47.733 回答
0

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

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

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

于 2013-04-04T10:09:05.873 回答