241 lines
4.8 KiB
C++
241 lines
4.8 KiB
C++
#ifndef HGL_THREAD_SWAP_DATA_INCLUDE
|
|
#define HGL_THREAD_SWAP_DATA_INCLUDE
|
|
|
|
#include<hgl/thread/ThreadMutex.h>
|
|
#include<hgl/thread/Semaphore.h>
|
|
|
|
namespace hgl
|
|
{
|
|
/**
|
|
* 单向多线程数据交换模板<br>
|
|
* 适用环境为多个线程向其投递数据,一个线程接收数据。接收方在每次处理前交换数据指针,以达到最小线程切换代价
|
|
*/
|
|
template<typename T> class SwapData
|
|
{
|
|
protected:
|
|
|
|
T data[2];
|
|
|
|
int post_index;
|
|
int recv_index;
|
|
|
|
ThreadMutex lock;
|
|
|
|
protected:
|
|
|
|
void _Swap()
|
|
{
|
|
if(recv_index){recv_index=0;post_index=1;}
|
|
else{recv_index=1;post_index=0;}
|
|
}
|
|
|
|
public:
|
|
|
|
SwapData()
|
|
{
|
|
recv_index=0;
|
|
post_index=1;
|
|
}
|
|
|
|
virtual ~SwapData()=default;
|
|
|
|
/**
|
|
* 获取投递方数据访问权
|
|
*/
|
|
T &GetPost()
|
|
{
|
|
lock.Lock();
|
|
|
|
return data[post_index];
|
|
}
|
|
|
|
/**
|
|
* 释放多线程投递方数据访问权
|
|
*/
|
|
void ReleasePost()
|
|
{
|
|
lock.Unlock();
|
|
}
|
|
|
|
/**
|
|
* 取得接收方数据访问权
|
|
*/
|
|
T &GetReceive(){return data[recv_index];}
|
|
|
|
/**
|
|
* 交换双方数据
|
|
*/
|
|
void Swap()
|
|
{
|
|
lock.Lock();
|
|
|
|
this->_Swap();
|
|
|
|
lock.Unlock();
|
|
}
|
|
|
|
/**
|
|
* 尝试交换双方数据
|
|
*/
|
|
bool TrySwap()
|
|
{
|
|
if(!lock.TryLock())
|
|
return(false);
|
|
|
|
this->_Swap();
|
|
|
|
lock.Unlock();
|
|
return(true);
|
|
}
|
|
|
|
#ifndef __APPLE__
|
|
/**
|
|
* 尝试交换双方数据
|
|
*/
|
|
bool WaitSwap(const double time_out)
|
|
{
|
|
if(!lock.WaitLock(time_out))
|
|
return(false);
|
|
|
|
this->_Swap();
|
|
|
|
lock.Unlock();
|
|
return(true);
|
|
}
|
|
#endif//__APPLE__
|
|
};//template<typename T> class SwapData
|
|
|
|
/**
|
|
* 信号自动交换数据访问模板
|
|
*/
|
|
template<typename T> class SemSwapData:public SwapData<T>
|
|
{
|
|
Semaphore sem;
|
|
|
|
public:
|
|
|
|
using SwapData<T>::SwapData;
|
|
~SemSwapData()=default;
|
|
|
|
/**
|
|
* 释放接收信号
|
|
* @param count 信号个数
|
|
*/
|
|
void PostSem(int count=1)
|
|
{
|
|
sem.Post(count);
|
|
}
|
|
|
|
/**
|
|
* 等待获取一个信号并交换前后台数据
|
|
* @param time_out 等待时长
|
|
*/
|
|
bool WaitSemSwap(const double time_out=5)
|
|
{
|
|
if(!sem.Acquire(time_out))
|
|
return(false);
|
|
|
|
this->Swap();
|
|
return(true);
|
|
}
|
|
|
|
/**
|
|
* 尝试获取一个信号并交换前后台数据
|
|
*/
|
|
bool TrySemSwap()
|
|
{
|
|
if(!sem.TryAcquire())
|
|
return(false);
|
|
|
|
this->Swap();
|
|
return(true);
|
|
}
|
|
};//template<typename T> class SemSwapData:public SwapData<T>
|
|
|
|
/**
|
|
* SwapData模板自动释放Post工具模板
|
|
*/
|
|
template<typename T> class PostToSwapData
|
|
{
|
|
SwapData<T> *swap_data;
|
|
T *post;
|
|
|
|
public:
|
|
|
|
PostToSwapData(SwapData<T> *sd)
|
|
{
|
|
swap_data=sd;
|
|
|
|
if(swap_data)
|
|
post=&(swap_data->GetPost());
|
|
else
|
|
post=nullptr;
|
|
}
|
|
|
|
~PostToSwapData()
|
|
{
|
|
if(swap_data)
|
|
swap_data->ReleasePost();
|
|
}
|
|
|
|
T *operator ->(){return post;}
|
|
};//template<typename T> class PostToSwapData
|
|
|
|
/**
|
|
* SemSwapData模板自动释放Post工具模板
|
|
*/
|
|
template<typename T> class PostToSemSwapData
|
|
{
|
|
SemSwapData<T> *swap_data;
|
|
T *post;
|
|
|
|
public:
|
|
|
|
PostToSemSwapData(SemSwapData<T> *sd)
|
|
{
|
|
swap_data=sd;
|
|
|
|
if(swap_data)
|
|
post=&(swap_data->GetPost());
|
|
else
|
|
post=nullptr;
|
|
}
|
|
|
|
~PostToSemSwapData()
|
|
{
|
|
if(swap_data)
|
|
{
|
|
swap_data->ReleasePost();
|
|
swap_data->PostSem();
|
|
}
|
|
}
|
|
|
|
T *operator ->(){return post;}
|
|
};//template<typename T> class PostToSemSwapData
|
|
|
|
/**
|
|
* 使用范例
|
|
*
|
|
* using EventQueue=Queue<int>;
|
|
* using MTEventQueue=SemSwapData<EventQueue>;
|
|
* using MTEventPost=PostToSemSwapData<EventQueue>;
|
|
*
|
|
* MTEventQueue mt_event_queue;
|
|
*
|
|
* 新方式:
|
|
* MTEventPost post(mt_event_queue);
|
|
*
|
|
* post.Push(1);
|
|
*
|
|
* 直接模式:
|
|
* EventQueue &eq=mt_event_queue.GetPost();
|
|
*
|
|
* eq->Push(1);
|
|
*
|
|
* mt_event_queue.ReleasePost();
|
|
* mt_event_queue.PostSem();
|
|
*
|
|
*/
|
|
}//namespace hgl
|
|
#endif//HGL_THREAD_SWAP_DATA_INCLUDE
|