我对多线程很陌生,我有一个单线程数据分析应用程序,它具有很好的并行化潜力,虽然数据集很大,但它并没有接近饱和硬盘读/写所以我想我应该利用现在标准中的线程支持并尝试加快速度。
经过一些研究,我认为生产者消费者是从磁盘读取数据并进行处理的好方法,我开始编写一个对象池,它将成为循环缓冲区的一部分,生产者将数据放入其中,消费者获取数据数据。当我写这门课时,感觉我在处理锁定和释放数据成员的方式上过于细化了。感觉就像有一半的代码在锁定和解锁,并且好像有大量的同步对象漂浮在周围。
所以我带着一个类声明和一个示例函数来找你,还有这个问题:这是否太细粒度了?粒度不够细?考虑不周?
struct PoolArray
{
public:
Obj* arr;
uint32 used;
uint32 refs;
std::mutex locker;
};
class SegmentedPool
{
public: /*Construction and destruction cut out*/
void alloc(uint32 cellsNeeded, PoolPtr& ptr);
void dealloc(PoolPtr& ptr);
void clearAll();
private:
void expand();
//stores all the segments of the pool
std::vector< PoolArray<Obj> > pools;
ReadWriteLock poolLock;
//stores pools that are empty
std::queue< int > freePools;
std::mutex freeLock;
int currentPool;
ReadWriteLock currentLock;
};
void SegmentedPool::dealloc(PoolPtr& ptr)
{
//find and access the segment
poolLock.lockForRead();
PoolArray* temp = &(pools[ptr.getSeg()]);
poolLock.unlockForRead();
//reduce the count of references in the segment
temp->locker.lock();
--(temp->refs);
//if the number of references is now zero then set the segment back to unused
//and push it onto the queue of empty segments so that it can be reused
if(temp->refs==0)
{
temp->used=0;
freeLock.lock();
freePools.push(ptr.getSeg());
freeLock.unlock();
}
temp->locker.unlock();
ptr.set(NULL,-1);
}
一些解释: First PoolPtr 是一个愚蠢的小指针对象,它存储指针和指针来自的池中的段号。
其次,这都是“模板化”的,但我把这些行拿出来试图减少代码块的长度
第三个 ReadWriteLock 是我使用互斥锁和一对条件变量组合而成的。