一直受惠于EasyDarWin开源项目,因此把自己的一些想法分享出来,希望能够帮助到其他人。
之前在推流测试中出现引用表异常的情况,经跟踪发现是内部封装的哈希表的hash函数对于传入的字符串无法得到一个唯一的key,下面是具体的hash函数
UInt32 OSRefTableUtils::HashString(StrPtrLen* inString) { Assert(inString != NULL); Assert(inString->Ptr != NULL); Assert(inString->Len > 0); if (inString == NULL || inString->Len == 0 || inString->Ptr == NULL) return 0; //make sure to convert to unsigned here, as there may be binary //data in this string UInt8* theData = (UInt8*)inString->Ptr; //divide by 4 and take the characters at quarter points in the string, //use those as the basis for the hash value UInt32 quarterLen = inString->Len >> 2; return (inString->Len * (theData[0] + theData[quarterLen] + theData[quarterLen * 2] + theData[quarterLen * 3] + theData[inString->Len - 1])); }其实对于hash函数本没没有什么错误,但我们的应用场景是对于一个传入的不同字符串参数,总能够可以进行快速的查询、插入等,而hash表从本质上来说是不可能避免冲突的,因此在此考虑使用在map的基础上来设计引用表。
在引用表的设计中参考了原Darwin的设计,并保持接口几乎一致,这样就比较便于修改。其中关键点有两个:1是对map的互斥和同步操作,在数据结构的设计上加入了互斥操作,可以放心的去调用。2是当释放对象时,该对象的引用必须为0,否则会产生不可想象的错误。下面看一下具体实现
#include "OSCond.h" #include "OSHeaders.h" class OSRefTableEx { public: class OSRefEx { private: void *mp_Object;//引用的对象或其余数据 int m_Count;//当前引用对象计数,只有为0时才允许对象销毁 OSCond m_Cond;//to block threads waiting for this ref. public: OSRefEx():mp_Object(NULL),m_Count(0){} OSRefEx(void * pobject):mp_Object(pobject),m_Count(0){} public: void *GetObjectPtr(){return mp_Object;} int GetRefNum(){return m_Count;} OSCond *GetCondPtr(){return &m_Cond;} void AddRef(int num){m_Count+=num;} }; private: map<string,OSRefTableEx::OSRefEx*> m_Map;//以string为key,以OSRefEx为value OSMutex m_Mutex;//提供对map的互斥操作 public: OSRefEx * Resolve(string keystring);//引用对象 OS_Error Release(string keystring);//释放引用 OS_Error Register(string keystring,void* pobject);//加入到map中 OS_Error UnRegister(string keystring);//从map中移除 OS_Error TryUnRegister(string keystring);//尝试移除,如果引用为0,则移除并返回true,否则返回false public: int GetEleNumInMap(){return m_Map.size();}//获得map中的元素个数 OSMutex *GetMutex(){return &m_Mutex;}//给外面提供互斥接口 map<string,OSRefTableEx::OSRefEx*> *GetMap(){return &m_Map;} };可以看到,引用表封装的map的key和value类型分别为string和OSRefEx*,使用string作为key是为了满足应用场景以及方便对原引用表进行修改,比较重要的是作为value的
OSRefEx*类型。OSRefex的设计参考了原OSRef类,提取了3个重要的属性来作为其成员变量。mp_Object表示string对应的对象指针,m_Count表示了对引用对象的引用次数,而m_Cond用于安全的来进行引用和释放引用。
有了OSRefex的设计,那么对于引用表的操作就是一些简单的map的增、删、查询操作了,相信对照代码一定可以看的很明白。
源码在下载频道,如发现错误,欢迎指教。