Многопоточный сервер IOCP и класс с подсчетом ссылок

Я работаю на сервере IOCP (перекрывающийся ввод-вывод, 4 потока, CreateIoCompletionPort, GetQueuedCompletionStatus, WSASend и т. Д.). И моя цель - отправить единый буфер с подсчетом ссылок для всех подключенных сокетов. (Я последовал предложению Лена Холгейта из этого сообщения WSAsend на все подключенные сокеты на многопоточном сервере iocp). После отправки буфера всем подключенным клиентам его следует удалить.

это класс с буфером для отправки

class refbuf
{
 private:
  int m_nLength;
  int m_wsk;
  char *m_pnData; // buffer to send
  mutable int mRefCount;

  public:
  ...

  void grab() const 
   {
          ++mRefCount;
   }

  void release() const
 {
    if(mRefCount > 0);
    --mRefCount;

    if(mRefCount == 0) {delete (refbuf *)this;}
 }  

    ...

char* bufadr() { return m_pnData;}


};

отправка буфера на все сокеты

refbuf *refb = new refbuf(4);
...
EnterCriticalSection(&g_CriticalSection);
pTmp1 = g_pCtxtList; // start of linked list with sockets
   while( pTmp1 ) 
   {  
     pTmp2 = pTmp1->pCtxtBack;
     ovl=TakeOvl();     // ovl -struct containing WSAOVERLAPPED 
     ovl->wsabuf.buf=refb->bufadr();// adress m_pnData from refbuf 
     ovl->rcb=refb;  //when GQCS get notification rcb is used to decrease mRefCount
     ovl->wsabuf.len=4;
     refb->grab();     // mRefCount ++
     WSASend(pTmp1->Socket, &(ovl->wsabuf),1,&dwSendNumBytes,0,&(ovl->Overlapped),   NULL);    
     pTmp1 = pTmp2;
  }
   LeaveCriticalSection(&g_CriticalSection);

и 1 из 4 потоков

 GetQueuedCompletionStatus(hIOCP, &dwIoSize,(PDWORD_PTR)&lpPerSocketContext, (LPOVERLAPPED *)&lpOverlapped, INFINITE);
 ... 
 lpIOContext = (PPER_IO_CONTEXT)lpOverlapped;
 lpIOContext->rcb->release();  //mRefCount --,if mRefCount reach 0, delete object

Я проверяю это с 5 подключенными клиентами, и кажется, что это работает. Когда GQCS получает все уведомления, mRefCount достигает 0 и выполняется удаление.

И мои вопросы: уместен ли такой подход? Что, если клиентов будет, например, 100 и более? Можно ли избежать ситуации, когда один поток может удалить объект, прежде чем другой все еще будет его использовать? Как реализовать атомарный счетчик ссылок в этом сценарии? Заранее спасибо.


person maciekm    schedule 15.12.2013    source источник
comment
Примечание: вместо того, чтобы называть метод grab и комментировать то, что он делает, просто назовите его addRef или incRefCount.   -  person usr    schedule 16.12.2013


Ответы (1)


Очевидные проблемы; в порядке важности ...

  1. Ваш класс refbuf не использует поточно-безопасную манипуляцию счетчиком ссылок. Используйте InterlockedIncrement() и т. Д.
  2. Я предполагаю, что TakeOvl() получает новую структуру OVERLAPPED и WSABUF за операцию.
  3. Ваше именование могло бы быть лучше, почему grab(), а не AddRef(), откуда TakeOvl() берется? Эти переменные Tmp являются чем-то, и наименее важным является то, что они «временные», поэтому назовите их в честь чего-то более важного. Пойдите, прочтите код, завершите.
person Len Holgate    schedule 15.12.2013
comment
1. InterlockedIncrement ()? хорошо, я погуглию и попробую. 2. Да, TakeOvl () возвращает указатель на уникальную расширенную перекрывающуюся структуру, которая также содержит структуру WSABUF для каждой операции. Хотя tmp-переменная ovl в цикле является указателем, в этом случае не должно быть проблем с выходом за пределы области действия (но я не уверен, что это правильное предположение). Когда GQCS получает уведомление, перекрывающаяся структура возвращается для повторного использования. В любом случае спасибо за ответ. - person maciekm; 16.12.2013