通用的多线程处理模型
好 草 多线程处理
放代码:
class
ThreadTest
{
public:
ThreadTest(){}
~ThreadTest(){}
void startup();
void addreq(int);
void _threadMain();
void _waitForNextRequest();
void _processNextRequest();
struct WorkerFunc OGRE_THREAD_WORKER_INHERIT
{
ThreadTest* mQueue;
WorkerFunc(ThreadTest* q)
: mQueue(q) {}
void operator()();
void run();
};
WorkerFunc* mWorkerFunc;
typedef std::deque<int> RequestQueue;
RequestQueue mRequestQueue;
OGRE_MUTEX(mRequestMutex)
OGRE_MUTEX(mProcessMutex)
OGRE_MUTEX(mResponseMutex)
OGRE_THREAD_SYNCHRONISER(mRequestCondition)
} ;
void ThreadTest::addreq( int i)
{
OGRE_LOCK_MUTEX(mRequestMutex)
mRequestQueue.push_back(i);
OGRE_THREAD_NOTIFY_ONE(mRequestCondition)
}
void ThreadTest::startup()
{
int i=3;
while(i>0)
{
mWorkerFunc = OGRE_NEW_T(WorkerFunc(this), MEMCATEGORY_GENERAL);
OGRE_THREAD_CREATE(t, *mWorkerFunc);
i--;
}
}
void ThreadTest::WorkerFunc:: operator ()()
{
mQueue->_threadMain();
}
void ThreadTest::WorkerFunc::run()
{
mQueue->_threadMain();
}
void ThreadTest::_threadMain()
{
while (true)
{
_waitForNextRequest();
_processNextRequest();
}
}
void ThreadTest::_waitForNextRequest()
{
OGRE_LOCK_MUTEX_NAMED(mRequestMutex, queueLock);
if (mRequestQueue.empty())
{
OGRE_THREAD_WAIT(mRequestCondition, mRequestMutex, queueLock);
}
}
void ThreadTest::_processNextRequest()
{
OGRE_LOCK_MUTEX(mProcessMutex)
{
OGRE_LOCK_MUTEX(mRequestMutex);
if (!mRequestQueue.empty())
{
int request = mRequestQueue.front();
mRequestQueue.pop_front();
cout<<request<<endl;
}
}
}
当然 里面用到了一些ogre中的线程宏,展开也就是boost的线程api:
{
public:
ThreadTest(){}
~ThreadTest(){}
void startup();
void addreq(int);
void _threadMain();
void _waitForNextRequest();
void _processNextRequest();
struct WorkerFunc OGRE_THREAD_WORKER_INHERIT
{
ThreadTest* mQueue;
WorkerFunc(ThreadTest* q)
: mQueue(q) {}
void operator()();
void run();
};
WorkerFunc* mWorkerFunc;
typedef std::deque<int> RequestQueue;
RequestQueue mRequestQueue;
OGRE_MUTEX(mRequestMutex)
OGRE_MUTEX(mProcessMutex)
OGRE_MUTEX(mResponseMutex)
OGRE_THREAD_SYNCHRONISER(mRequestCondition)
} ;
void ThreadTest::addreq( int i)
{
OGRE_LOCK_MUTEX(mRequestMutex)
mRequestQueue.push_back(i);
OGRE_THREAD_NOTIFY_ONE(mRequestCondition)
}
void ThreadTest::startup()
{
int i=3;
while(i>0)
{
mWorkerFunc = OGRE_NEW_T(WorkerFunc(this), MEMCATEGORY_GENERAL);
OGRE_THREAD_CREATE(t, *mWorkerFunc);
i--;
}
}
void ThreadTest::WorkerFunc:: operator ()()
{
mQueue->_threadMain();
}
void ThreadTest::WorkerFunc::run()
{
mQueue->_threadMain();
}
void ThreadTest::_threadMain()
{
while (true)
{
_waitForNextRequest();
_processNextRequest();
}
}
void ThreadTest::_waitForNextRequest()
{
OGRE_LOCK_MUTEX_NAMED(mRequestMutex, queueLock);
if (mRequestQueue.empty())
{
OGRE_THREAD_WAIT(mRequestCondition, mRequestMutex, queueLock);
}
}
void ThreadTest::_processNextRequest()
{
OGRE_LOCK_MUTEX(mProcessMutex)
{
OGRE_LOCK_MUTEX(mRequestMutex);
if (!mRequestQueue.empty())
{
int request = mRequestQueue.front();
mRequestQueue.pop_front();
cout<<request<<endl;
}
}
}
#define OGRE_LOCK_MUTEX(name) boost::recursive_mutex::scoped_lock ogrenameLock(name);
#define OGRE_LOCK_MUTEX_NAMED(mutexName, lockName) boost::recursive_mutex::scoped_lock lockName(mutexName);
#define OGRE_THREAD_WAIT(sync, mutex, lock) sync.wait(lock);
#define OGRE_THREAD_NOTIFY_ONE(sync) sync.notify_one();
#define OGRE_THREAD_NOTIFY_ALL(sync) sync.notify_all();
#define OGRE_THREAD_SYNCHRONISER(sync) boost::condition sync;
#define OGRE_MUTEX(name) mutable boost::recursive_mutex name;
#define OGRE_THREAD_WAIT(sync, mutex, lock) sync.wait(lock);
主线程不断调用addreq()来增加请求并通知线程后马上返回 线程在得到通知后从阻塞中醒来处理请求
OGRE_LOCK_MUTEX(name):就是在范围内只允许有一个线程进入
OGRE_THREAD_WAIT(mRequestCondition, mRequestMutex, queueLock):该宏会失去queueLock,阻塞当前线程直到被通知,在返回前取得queueLock
来看_waitForNextRequest()的代码:
_waitForNextRequest()
{
OGRE_LOCK_MUTEX_NAMED(mRequestMutex, queueLock);
if (mRequestQueue.empty())
{
OGRE_THREAD_WAIT(mRequestCondition, mRequestMutex, queueLock);
}
}
首先取得范围锁queueLock,如果mRequestQueue为空,就等着,同时要注意,由于失去queueLock,其他线程会得到queueLock,并再次导致queueLock的变化
如果有三个线程,分别是1,2,3
假设线程1最先取得queueLock,然后被阻塞,同时线程2或者3会在线程1失去queueLock时取得queueLock,最终,三个线程都会被阻塞,queueLock为失去
继续往下走,假设这时主线程addreq(),那么有一个线程会被唤醒,同时得到queueLock,然后跳出该函数时,queueLock也随着超出范围变为失去,然后来看
下一个函数_processNextRequest()的代码:
_processNextRequest()
{
Request* request = 0;
{
OGRE_LOCK_MUTEX(mRequestMutex)
if (!mRequestQueue.empty())
{
request = mRequestQueue.front();
mRequestQueue.pop_front();
}
}
if (request)
{
processRequestResponse(request, false);
}
函数内容改了下以看得更加清楚,函数取得mRequestMutex,当其队列非空时,从队列中弹出一个请求,随后丢失mRequestMutex,并处理request
在处理完request后,将结果放进一个响应队列中,主线程在其循环中将会看到,整个流程就是这样子
总结:请求队列要注意是否为空,由于有多个线程,需要将其设为阻塞并在需要时唤醒