您的位置:首页 > 编程语言

通用编程能力训练 -- 设计心得:分步载入的改造(包含异步IO练习)

2009-10-11 15:05 441 查看
目标:将一个顺序载入的系统变成分步载入的系统。

 

动机:

也许你会说背景线程 可以达到更好的效果, 但是我想说的是在一些情况下是无法使用多线程的。

比如装载Shader程序,这些程序都需要使用CPU进行本地编译。

这时支持分步载入的系统就能根据情况来分散载入任务,平滑资源载入的过程,可以让系统充分利用时间来使前台功能看起来平滑。

另外一个理由是性能,基于多线程的系统总是会为各种锁支付额外的开销,对于Ogre而言,这2种工作模式的性能差异可以达到30%以上。

注意,这个改造方案和多线程工作模式不冲突。

 

步骤:

1、确保存在 isLoaded() 或类似方法,因为分步载入的结构和异步结构一致.

2、确保存在一个用于记录所有的加载任务的数据成员,如果没有就定义一个.

3、添加一个游标变量记录当前正在处理哪个子对象,可以是一个对象引用、上值、索引、迭代器等.

4、添加一个用于步进载入的函数 bool loadNext(), 在该函数中发起"当前正在处理的子对象"的加载, 并将游标指向下一个对象.

5、添加一个用于直接载入的函数 void loadDirectly(), 该函数使用 基于 while( loadNext()) 的结构来实现自己.

6、在创建母对象的接口上添加一个 bool manualLoad 变量,用于确定是否使用步进加载,或使用原有的直接加载方式.

 

范例:(注意下面的 + expand / sourceview / plaincopy to clipboard / print / ?)

 

 
// MultiThreadTest_Console2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "windows.h"
#include <string>
#include <vector>
#include <algorithm>
// 模拟资源加载
// time: 186min;
unsigned int gFrameIndex;
// 子对象
class SubObject
{
public:
SubObject(const std::string& name, unsigned int size)
:mName(name)
,mSize(size)
{
}
std::string mName;
unsigned int mSize;
};
// 子对象加载器
class SubObjectManager/* : public Singleton<SubObjectManager>*/
{
public:
typedef std::vector<SubObject*> SubObjects;
public:
SubObjectManager(){}
~SubObjectManager(){}

public:
SubObject* load(const std::string& name)
{
unsigned int size = rand()%100;
std::string _name = name;
Sleep(size);
SubObject* so = new SubObject(_name, size);
mSubObjects.push_back(so);
return so;
}
SubObject* getSubObject(const std::string& name)
{
for( SubObjects::iterator it = mSubObjects.begin();
it != mSubObjects.end(); ++it)
{
if((*it)->mName == name)
return *it;
}
return NULL;
}
private:
SubObjects mSubObjects;
};
struct Task;
class AnSyncResourceLoaderListener
{
public:
virtual void processCompleted(const Task* task){};
};
struct Task
{
typedef std::vector<AnSyncResourceLoaderListener*> Lisnters;
unsigned int mID;
std::string mName;
Lisnters mLisnters;

void megry( const Task& other)
{
if( !isSameTask(other))
return;
for( Lisnters::const_iterator other_it = other.mLisnters.begin();
other_it != other.mLisnters.end(); ++other_it)
{
Lisnters::iterator this_it = std::find(mLisnters.begin(), mLisnters.end(), *other_it);
if( this_it == mLisnters.end())
{
mLisnters.push_back(*other_it);
}
}
}
bool isSameTask( const Task& other)
{
return other.mName == mName;
}
void notifyCompleted()
{
for( Lisnters::iterator it = mLisnters.begin();
it != mLisnters.end(); ++it)
{
(*it)->processCompleted(this);
}
}
bool operator ==(const Task& other)
{
return mID == other.mID && mName == other.mName;
}
};
class AnSyncResourceLoader/* : public Singleton<AnSyncResourceLoader>*/
{
public:
typedef std::vector<Task> TaskQuene;
public:
AnSyncResourceLoader(SubObjectManager* pSubObjectManager)
:mNextTaskID(0)
,mSubObjectManager(pSubObjectManager)
{
InitializeCriticalSection (&mRawTaskQueneCS);
InitializeCriticalSection (&mCompletedTaskQueneCS);
}
~AnSyncResourceLoader()
{
DeleteCriticalSection (&mRawTaskQueneCS);
DeleteCriticalSection (&mCompletedTaskQueneCS);
}
public:
void pushRawTask( Task& task)
{
EnterCriticalSection (&mRawTaskQueneCS) ;
// 策略
// 1、已经加载了--》直接添加到完成队列
// 2、已经提交该任务了(不管是否正在处理)--》合并 Listener
// 3、不存在--》直接添加
// 情况1
TaskQuene::iterator raw_it = std::find(mRawTaskQuene.begin(),mRawTaskQuene.end(),task);
if( raw_it != mRawTaskQuene.end())
{
raw_it->megry(task);
}
// 情况2
else
{
TaskQuene::iterator completed_it = std::find(mCompletedTaskQuene.begin(),mCompletedTaskQuene.end(),task);
if( completed_it != mCompletedTaskQuene.end())
{
completed_it->megry(task);
}
// 情况3
else
{
task.mID = mNextTaskID++;
mRawTaskQuene.push_back(task);
}
}
LeaveCriticalSection (&mRawTaskQueneCS) ;
}
Task popRawTask(const Task& task)
{
EnterCriticalSection (&mRawTaskQueneCS) ;
Task out;
TaskQuene::iterator raw_it = std::find(mRawTaskQuene.begin(),mRawTaskQuene.end(),task);
if( raw_it != mRawTaskQuene.end())
{
out = *raw_it;
mRawTaskQuene.erase(raw_it);
}
return out;
LeaveCriticalSection (&mRawTaskQueneCS) ;
}
void pushCompletedTask( const Task& task)
{
EnterCriticalSection (&mCompletedTaskQueneCS);
// 策略
// 1、已经存在,还没通知主线程将回调发送出去--》合并Listener
// 2、不存在--》直接添加
// 情况1
TaskQuene::iterator completed_it = std::find(mCompletedTaskQuene.begin(),mCompletedTaskQuene.end(),task);
if( completed_it != mCompletedTaskQuene.end())
{
completed_it->megry(task);
}
// 情况2
else
{
mCompletedTaskQuene.push_back(task);
}
LeaveCriticalSection (&mCompletedTaskQueneCS);
}
Task popCompletedTask(const Task& task)
{
Task out;
EnterCriticalSection (&mCompletedTaskQueneCS) ;
TaskQuene::iterator completed_it = std::find(mCompletedTaskQuene.begin(),mCompletedTaskQuene.end(),task);
if( completed_it != mCompletedTaskQuene.end())
{
out = *completed_it;
mCompletedTaskQuene.erase(completed_it);
}
LeaveCriticalSection (&mCompletedTaskQueneCS) ;
return out;
}
public:
// 多线程函数
DWORD WINAPI doLoad( LPVOID lpThreadParameters)
{
while(true)
{
if(	mRawTaskQuene.empty())
continue;
Task task = mRawTaskQuene.front();
mSubObjectManager->load(task.mName);
popRawTask(task);
pushCompletedTask(task);
}
return 0;
}
// 主线程函数
public:
void notifyCompleted()
{
EnterCriticalSection (&mCompletedTaskQueneCS);
for( TaskQuene::iterator it = mCompletedTaskQuene.begin();
it != mCompletedTaskQuene.end(); ++it)
{
it->notifyCompleted();
}
mCompletedTaskQuene.clear();
LeaveCriticalSection (&mCompletedTaskQueneCS);
}

private:
CRITICAL_SECTION mRawTaskQueneCS;
CRITICAL_SECTION mCompletedTaskQueneCS;
TaskQuene mRawTaskQuene;
TaskQuene mCompletedTaskQuene;
unsigned int mNextTaskID;
SubObjectManager* mSubObjectManager;
};
class BaseObject : public AnSyncResourceLoaderListener
{
public:
typedef std::vector<std::string> RawResourceList;
typedef std::vector<SubObject*> SubObjects;
public:
BaseObject(const RawResourceList& resources,AnSyncResourceLoader* pLoader)
:mNextLoadIndex(0)
,mCompletedCount(0)
,mLoaded(false)
,mAllRawResourceLoading(false)
,mLoader(pLoader)
{
mResources = resources;
}
~BaseObject(){}
public:
virtual void processCompleted(const Task* task)
{
printf("加载完成[%s],frame[%u]/n", task->mName.c_str(), gFrameIndex);
if(++mCompletedCount == mResources.size())
mLoaded = true;
};
public:
bool loadNext()
{
if( mAllRawResourceLoading)
return false;
std::string taskName = mResources[mNextLoadIndex];
Task task;
task.mLisnters.push_back(this);
task.mName = taskName;
mLoader->pushRawTask(task);
printf("发起加载[%s],frame[%u]/n", taskName.c_str(), gFrameIndex);
mNextLoadIndex++;
if( mNextLoadIndex >= mResources.size())
mAllRawResourceLoading = true;
return true;
}
bool isLoaded()
{
return mLoaded;
}
private:
RawResourceList mResources;
SubObjects mSubObjects;
bool mLoaded;
bool mAllRawResourceLoading;
unsigned int mNextLoadIndex;
unsigned int mCompletedCount;
AnSyncResourceLoader* mLoader;
};
DWORD WINAPI doLoad( LPVOID lpThreadParameters)
{
AnSyncResourceLoader* pAnSyncResourceLoader = (AnSyncResourceLoader*)(lpThreadParameters);
return pAnSyncResourceLoader->doLoad(lpThreadParameters);
}
int _tmain(int argc, _TCHAR* argv[])
{
SubObjectManager subObjectManager;
AnSyncResourceLoader anSyncResourceLoader(&subObjectManager);
HANDLE hThread = CreateThread( NULL, 0, doLoad, &anSyncResourceLoader, 0, NULL);

BaseObject::RawResourceList r;
r.push_back("dasdasda");
r.push_back("21212");
r.push_back("xxxxxsda");
r.push_back("5555555sda");
BaseObject* bo = new BaseObject(r,&anSyncResourceLoader);
gFrameIndex = 0;
while(true)
{
gFrameIndex++;
// 更新
anSyncResourceLoader.notifyCompleted();
if(!bo->isLoaded())
bo->loadNext();
else
break;
}
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息