Linux下Epoll框架——容器部分

容器是存储检索各类数据的利器,但是STL提供的内容使用起来还是不方便,所以对部分代码做一些封装,而且对于map来说,windows和linux下的用法不一样,曾花了很多时间来编写这个跨平台的map。

正如第一篇所说,由于跨平台代码很难看,只维护了一个Linux的版本,但map是个例外,以后还会有少量例外。

 

1. 对Queue的封装。这个queue并不是最小粒度的封装,我加了一个semaphore,用来实现生产者和消费者模型。

其实也可以把semaphore移到queue之外,和queue本身分开来实现生产者消费者。我是为了效率,为了方便,呵呵,各位就见仁见智吧。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
#include <deque>

#include 
"Common.h"
#include 
"Types.h"

namespace GameMate{

template
<class V>
class Queue
{
public:
    
    Queue() {} 
    
~Queue() {}
    
    
void Push(V value)
    {
        mutexObject.Lock();
        valueQueue.push_back(value);
        mutexObject.Unlock();
        semaphoreObject.Unlock();
    }
    
    V Pop()
    {
        V tempValue;
        semaphoreObject.Lock();
        mutexObject.Lock();
        tempValue 
= valueQueue.front();
        valueQueue.pop_front();
        mutexObject.Unlock();
        
return tempValue;
    }
    
    uint32 Size()
    {
        uint32 itemCount;
        mutexObject.Lock();
        itemCount 
= valueQueue.size();
        mutexObject.Unlock();
        
return itemCount;
    }
    
private:
    Mutex mutexObject;
    Semaphore semaphoreObject;
    std::deque
<V> valueQueue;
        
private:
    DISALLOW_COPY_AND_ASSIGN(Queue);        
};

 

Mutex的定义如下,用来实现跨平台:

 #ifdef _LINUX_

#include "Sync.h"


typedef ThreadMutex Mutex;
typedef ThreadReadWriteMutex RWMutex;
typedef Semaphore Semaphore;

#elif defined(_WIN32)

#include "CriticalSection.h"
typedef CriticalSection Mutex;

#else


#endif

 

 

DISALLOW_COPY_AND_ASSIGN的宏是参考Google C++ Coding Style,用来限制类型复制和拷贝等对class类型变量的误操作,也可以提高性能,减少编译器自作主张为我们生成一些无法预料的代码。

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
    TypeName(
const TypeName&);               \
    
void operator=(const TypeName&)

使用时,请在class的声明中加入以下的代码:

class A

{

private:

  DISALLOW_COPY_AND_ASSIGN(A);

}

CriticalSection是我对Windows下CRITICAL_SETCION的一个简单封装,只要提供Lock和Unlock接口就好了,Lock就是Enter,Unlock就是Leave,大家可以自己动手封装一下

 

2. 对map的封装

 

 

ContractedBlock.gif ExpandedBlockStart.gif Code
template <class K, class V>
class HashMap
{
public:
    HashMap(
void) {}
    
virtual ~HashMap(void) {}

    
bool Add(K key, V value)
    {
#ifndef _LINUX_
        std::pair
<std::map<K, V>::iterator, bool> result;
#else
        
bool result;
#endif

        mutexObject.Lock();

#ifndef _LINUX_
        result 
= keyValueMap.insert(std::map<K, V>::value_type(key, value));
#else
        result 
= keyValueMap.insert(std::pair<K, V>(key, value)).second;
#endif

        mutexObject.Unlock();

#ifndef _LINUX_
        
return result.second;
#else
        
return result;
#endif
    }


    
void RemoveKey(K key)
    {
        mutexObject.Lock();
        keyValueMap.erase(key);
        mutexObject.Unlock();
    }

    
/**
    * @bug 如果V不是一个指针类型,那么调用该函数会出问题,但都是编译期问题,所以还不要紧
    
*/
    
void RemoveAndDestroyKey(K key)
    {
        mutexObject.Lock();

        V value 
= keyValueMap[key];

        
if(NULL != value)
        {
            delete value;
        }
        
        keyValueMap.erase(key);
        mutexObject.Unlock();
    }

    
void RemoveValue(V value)
    {

#ifndef _LINUX_
        std::map
<K, V>::iterator iter;
#else
        typename std::map
<K, V>::iterator iter;
#endif

        mutexObject.Lock();

        
for(iter = keyValueMap.begin(); iter != keyValueMap.end(); ++iter)
        {
            
if(iter->second == value)
            {
                keyValueMap.erase(iter);
                
break;
            }
        }

        mutexObject.Unlock();
    }

    
/**
    * @bug 如果V不是一个指针类型,那么调用该函数会出问题,但都是编译期问题,所以还不要紧
    
*/
    
void RemoveAndDestroyValue(V value)
    {
#ifndef _LINUX_
        std::map
<K, V>::iterator iter;
#else
        typename std::map
<K, V>::iterator iter;
#endif


        mutexObject.Lock();

        
for(iter = keyValueMap.begin(); iter != keyValueMap.end(); iter++)
        {
            
if(iter->second == value)
            {
                delete iter
->second;
                keyValueMap.erase(iter);
                
break;
            }
        }

        mutexObject.Unlock();
    }

    
void RemoveAll()
    {
        mutexObject.Lock();
        keyValueMap.clear();
        mutexObject.Unlock();
    }


    
/**
     * @bug 如果V不是一个指针类型,那么调用该函数会出问题,但都是编译期问题,所以还不要紧
     
*/
    
void RemoveAllAndDestroy()
    {
#ifndef _LINUX_
        std::map
<K, V>::iterator iter;
#else
        typename std::map
<K, V>::iterator iter;
#endif

        mutexObject.Lock();

        
for(iter = keyValueMap.begin(); iter != keyValueMap.end(); iter++)
        {
            
if(NULL != iter->second)
            {
                delete iter
->second;
                iter
->second = NULL;
            }
        }

        keyValueMap.clear();
        mutexObject.Unlock();
    }

    
bool Empty()
    {
        
bool isEmpty = false;

        mutexObject.Lock();
        isEmpty 
= (bool)keyValueMap.empty();
        mutexObject.Unlock();

        
return isEmpty;
    }

    V GetValueByKey(K key)
    {
        V value;

        mutexObject.Lock();
        
if(keyValueMap.find(key) != keyValueMap.end())
        {
            value 
= keyValueMap[key];
        }
        
else
        {
            value 
= 0;
        }
        mutexObject.Unlock();

        
return value;            
    }


    
    std::map
<K, V>& GetInnerMap() 
    { 
        
return keyValueMap; 
    }


private:
    std::map
<K, V> keyValueMap;
    Mutex mutexObject;

private:
    DISALLOW_COPY_AND_ASSIGN(HashMap);
};

 

RemoveAllAndDestroy函数有潜在的bug。

因为我是为了自己的应用方便,把HashMap<int, void *>这样用的时候,希望在清除map所有项的同时也释放内存,所以就有这个函数。

另外,可以用读写锁ThreadReadWriteMutex替代Mutex,理论上性能高一点,但没有测试过。我封装了一个RWHashMap,采用读写锁的。跟HashMap类似,就不赘述了。

还有,为了应用方便,还定义了一个BiHashMap,用于双向映射。BiHashMap<K, V> myMap; 里面包含了一个<K, V>的map,还有一个<V, K>的map。有兴趣的给我写邮件吧。

 

3. 对链表的封装(C形式的,借鉴了Codeproject的一个开源系统)

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class NodeList;

class Node
{
public:
    
    Node 
*Next() const;
    
void Next(Node *pNext);

    
void AddToList(NodeList *pList);
    
void RemoveFromList();

protected:

    Node();
    
~Node();

private :
    friend 
class NodeList;
    
void Unlink();

public:
    Node 
*m_pNext;
    Node 
*m_pPrev;
    NodeList 
*m_pList;

private:
    DISALLOW_COPY_AND_ASSIGN(Node);
};


Node::Node(
void)
    :m_pNext(NULL), 
     m_pPrev(NULL), 
     m_pList(NULL) 
{
}

Node::
~Node(void)
{
    
try
    {
        RemoveFromList();   
    }
    
catch(dot.gif)
    {
    }

    m_pNext 
= NULL;
    m_pPrev 
= NULL;
    m_pList 
= NULL;
}

Node 
*Node::Next() const
{
    
return m_pNext;
}

void Node::Next(Node *pNext)
{
    m_pNext 
= pNext;

    
if (pNext)
    {
        pNext
->m_pPrev = this;
    }
}

void Node::AddToList(NodeList *pList)
{
    
/*
    if(pList == NULL)
    {
        printf("List is Null!\n");
    }
    else
    {
        printf("List is not NULL!\n");
    }
    
*/
    m_pList 
= pList;
}

void Node::RemoveFromList()
{
    
//printf("In RemoveFromList()! %p\n", m_pList);
    if (m_pList)
    {
        m_pList
->RemoveNode(this);
        
//printf("Remove it!\n");
    }
}

void Node::Unlink()
{
    
if (m_pPrev)
    {
        m_pPrev
->m_pNext = m_pNext;
    }

    
if (m_pNext)
    {
        m_pNext
->m_pPrev = m_pPrev;
    }

    m_pNext 
= NULL;
    m_pPrev 
= NULL;

    m_pList 
= NULL;
}


///NodeList.h////
class NodeList
{
public:
    NodeList(
void);
    
virtual ~NodeList(void);

public:
    
void PushNode(Node *pNode);
    Node 
*PopNode();
    Node 
*Head() const;
    uint32 Count() 
const;
    
bool Empty() const;

private :
    friend 
void Node::RemoveFromList();
    
void RemoveNode(Node *pNode);
    Node 
*m_pHead; 
    uint32 m_numNodes;

private:
    DISALLOW_COPY_AND_ASSIGN(NodeList);
};


//
template <class T>
class TemplateNodeList : public NodeList
{
public :

    T 
*PopNode();
    T 
*Head() const;
    
static T *Next(const T *pNode);
};

template 
<class T>
*TemplateNodeList<T>::PopNode()
{
    
return static_cast<T*>(NodeList::PopNode());
}

template 
<class T>
*TemplateNodeList<T>::Head() const
{
    
return static_cast<T*>(NodeList::Head());
}

template 
<class T>
*TemplateNodeList<T>::Next(const T *pNode)
{
    
return static_cast<T*>(pNode->Next());
}


////NodeList.cpp/NodeList::NodeList() 
:m_pHead(NULL), 
m_numNodes(
0
{
}

NodeList::
~NodeList(void)
{
}


void NodeList::PushNode(Node *pNode)
{
    pNode
->AddToList(this); //仅仅添加到列表

    pNode
->Next(m_pHead);

    m_pHead 
= pNode;

    
++m_numNodes;
}

Node 
*NodeList::PopNode()
{
    Node 
*pNode = m_pHead;

    
if (pNode)
    {
        RemoveNode(pNode);
    }

    
return pNode;
}

Node 
*NodeList::Head() const
{
    
return m_pHead;
}


uint32 NodeList::Count() 
const
{
    
return m_numNodes;
}

bool NodeList::Empty() const
{
    
return (0 == m_numNodes);
}

void NodeList::RemoveNode(Node *pNode)
{
    
//printf("%d\n", m_numNodes);
    if (pNode == m_pHead)
    {
        m_pHead 
= pNode->Next();
    }

    pNode
->Unlink();

    
--m_numNodes;
    
//printf("%d\n", m_numNodes);
}

 

Node的用处在于可对很多资源做缓存处理。比如网络socket。建立一个socket的系统开销是很大的,所以可以预先把socket创建好,然后放到链表里。

如何使用呢?例如我定义了一个缓冲区类Buffer,我想对这个类做缓存处理,因为内存的分配与释放也是开销很大的。就可以:

class Buffer : public Node

{

}

后面会谈到Buffer类,所以这里就不详述了。

 

 

 

 

 

转载于:https://www.cnblogs.com/miscab/archive/2009/05/21/1486530.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值