本文主要是介绍Darwin中OSRef和OSHashTable类的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
//哈希表被设计成模版类的形式
#include "../WinNTSupport/Win32header.h"#include <iostream>
using namespace std;
#include <string>#include <OSCond.h>
#include <OSRef.h>
#include "getopt.h"
#include "FilePrefsSource.h"#include "RunServer.h"
#include "QTSServer.h"
#include "QTSSExpirationDate.h"
#include "GenerateXMLPrefs.h"// #include "OSHashTable.h"
#include "MyAssert.h"
typedef OSHashTable<OSRef, OSRefKey> OSRefHashTable;
typedef OSHashTableIter<OSRef,OSRefKey> OSRefHashTableIter;
int main(int argc, char * argv[])
{OSRefHashTable fTable(1000);
for (int i=0; i< 5 ;i ++)
{char *buf = new char[100];
memset(buf,0,100);sprintf(buf,"%d%d%d%d",i,i,i,i);
StrPtrLen ptr(buf);OSRef *fRef = new OSRef;
fRef->Set(ptr,NULL);
OSRefKey key(fRef->GetString());
OSRef* duplicateRef = fTable.Map(&key);
if (duplicateRef != NULL)
{
continue;
}
fTable.Add(fRef);
}OSRefHashTableIter tableIter(&fTable);
OSRef *pTemp = NULL;
while((pTemp = tableIter.GetCurrent()) != NULL)
{
char *pbuf = pTemp->GetString()->GetAsCString();
cout << pbuf <<" index:"<<tableIter.GetCurIndex()<< endl;
tableIter.Next();
}return 0;
}
template<class T, class K>
class OSHashTable {
public:OSHashTable( UInt32 size ) //构造函数{fHashTable = new ( T*[size] );//初始化大小Assert( fHashTable );memset( fHashTable, 0, sizeof(T*) * size );//设置初始值fSize = size;/*下面的代码决定用哪种方式为哈希表的键值计算索引;
如果哈希表的大小不是2的幂,只好采用对fSize求余的方法;
否则可以直接用掩码的方式,这种方式相对速度更快*/ fMask = fSize - 1;if((fMask & fSize) != 0)//判断是不是2的幂,确定使用何种哈希函数(ComputeIndex)fMask = 0;fNumEntries = 0;}~OSHashTable() //析构{delete [] fHashTable;}voidAdd( T* entry ) { //加入元素,有标记代码可以看出,此处解决冲突的方式采用了链地址法Assert( entry->fNextHashEntry == NULL );Kkey( entry );UInt32 theIndex = ComputeIndex( key.GetHashKey() );entry->fNextHashEntry = fHashTable[theIndex ];fHashTable[ theIndex ] = entry;fNumEntries++;}voidRemove( T* entry )//移除元素{Kkey( entry );UInt32 theIndex = ComputeIndex( key.GetHashKey() );T*elem = fHashTable[ theIndex ];T*last = NULL;while (elem && elem != entry) {last = elem;elem = elem->fNextHashEntry;}if( elem ) // sometimes remove is called 2x ( swap, then un register ){Assert(elem);if (last)last->fNextHashEntry = elem->fNextHashEntry;elsefHashTable[ theIndex ] =elem->fNextHashEntry;elem->fNextHashEntry = NULL;fNumEntries--;}}T* Map(K* key ) //查找对象{UInt32 theIndex = ComputeIndex( key->GetHashKey() );T*elem = fHashTable[ theIndex ];while (elem) {K elemKey( elem );if (elemKey == *key)break;elem = elem->fNextHashEntry;}return elem;}UInt64GetNumEntries() { return fNumEntries; }UInt32GetTableSize() { return fSize; }T*GetTableEntry( int i ) { return fHashTable[i]; }private:T**fHashTable;UInt32fSize;UInt32fMask;UInt64fNumEntries;UInt32 ComputeIndex(UInt32 hashKey ){if (fMask)return( hashKey & fMask );//掩码方式elsereturn( hashKey % fSize );// 除留取余法}
};
//实现了一个hash表迭代器的功能
template<class T, class K>
class OSHashTableIter {
public:OSHashTableIter( OSHashTable<T,K>* table ){fHashTable = table;First();}voidFirst(){for(fIndex = 0; fIndex < fHashTable->GetTableSize(); fIndex++) {fCurrent = fHashTable->GetTableEntry( fIndex );if (fCurrent)break;}}voidNext(){fCurrent = fCurrent->fNextHashEntry;if(!fCurrent) {for (fIndex = fIndex + 1; fIndex < fHashTable->GetTableSize();fIndex++) {fCurrent =fHashTable->GetTableEntry( fIndex );if (fCurrent)break;}}}Bool16IsDone(){return( fCurrent == NULL );}T*GetCurrent() { return fCurrent; }private:OSHashTable<T,K>* fHashTable;T*fCurrent;UInt32fIndex;
};
引用表头文件定义,详细的代码请参考源码,此处只结合实例讲解几个主要的函数
//结合实例说明常用的方法
服务器网络模型中有个很重要的类EventContext, EventContext.h中包含EventContext类和EventThread类的定义
每一个EventContext类中都有一个引用对象,如下图
在每次执行RequestEvent函数时,就会执行以下代码(EventContext.cpp182行)
if (!compare_and_store(8192, WM_USER,&sUniqueID))
fUniqueID = (PointerSizedInt)atomic_add(&sUniqueID, 1); //获取一个唯一标识
fRef.Set(fUniqueIDStr, this);//对引用对象赋值
void Set(const StrPtrLen&inString, void* inObjectP)
{
fString = inString; fObjectP =inObjectP;
fHashValue =OSRefTableUtils::HashString(&fString);
}
fString作为索引,fObjectP保存对象,fHashValue根据索引计算出一个hash值
fEventThread->fRefTable.Register(&fRef);//把这个引用对象加入到EventThread中的引用表中(其实就是hash表),fRefTable是OSRefTable类的实例,而类中操作的表是OSRefHashTable类型(typedef OSHashTable<OSRef, OSRefKey>OSRefHashTable;)
OS_ErrorOSRefTable::Register(OSRef* inRef)
{
if (inRef == NULL)
return EPERM;
OSMutexLocker locker(&fMutex);
if (inRef->fString.Ptr == NULL || inRef->fString.Len == 0)
{ return EPERM;
}
// Check for a duplicate. In this function, if there is a duplicate,
// return an error, don't resolve the duplicate
OSRefKey key(&inRef->fString);
OSRef* duplicateRef = fTable.Map(&key);//查找有没有重复的,没有则加入到hash表中
if (duplicateRef != NULL)
return EPERM;
// There is no duplicate, so add this ref into the table
fTable.Add(inRef);
return OS_NoErr;
}
::memset( &fEventReq, '\0',sizeof(fEventReq));//下面的代码其实就是把socket加入到select监视中,由于本文主要讲解下引用表相关类的使用,所以此处不再详细描述
fEventReq.er_type = EV_FD;
fEventReq.er_handle = fFileDesc;
fEventReq.er_eventbits = theMask;
fEventReq.er_data = (void*)fUniqueID;
if (select_watchevent(&fEventReq, theMask) !=0)
========以上代码描述了构造一个ref,然后加入reftable中的操作
在EventThread的线程执行函数Entry中,使用了reftable查找EventContext对象
当select返回一个可操作的socket时,执行了以下代码,
if (theCurrentEvent.er_data != NULL)// theCurrentEvent就是select返回的数据
{
StrPtrLen idStr((char*)&theCurrentEvent.er_data,sizeof(theCurrentEvent.er_data));
//返回的数据用于构造一个id,这个id其实就是在上一步中得到的唯一标识,如下图
OSRef* ref = fRefTable.Resolve(&idStr);//根据这个唯一标识获取到引用对象,其实就是通过hash类中map函数去查找对象,然后把引用对象的引用计数+1
if (ref != NULL)
{
EventContext* theContext = (EventContext*)ref->GetObject();
theContext->ProcessEvent(theCurrentEvent.er_eventbits);
fRefTable.Release(ref);//把引用对象的引用计数-1,然后设置事件为有信号,确保唤醒等待该资源被释放的对象
}
}
以上说明是通过darwin中一个使用实例,为了方面理解引用表和哈希表的使用(OSRef和OSHashTable)
这篇关于Darwin中OSRef和OSHashTable类的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!