私はマルチスレッドにまったく慣れていません。並列化の可能性がかなりあるシングルスレッドのデータ分析アプリを持っています。データセットは大きいですが、ハードディスクの読み取り/書き込みを飽和させることはありません。現在標準になっているスレッド化のサポートを利用して、高速化を図るべきです。
いくつかの調査の後、ディスクからデータを読み取って処理するにはプロデューサー コンシューマーが適切なアプローチであると判断し、プロデューサーがデータを置き、コンシューマーが取得する循環バッファーの一部となるオブジェクト プールの作成を開始しました。データ。クラスを書いているときに、データ メンバーのロックと解放の処理方法が細かすぎるように感じました。コードの半分がロックとロック解除を行っており、非常に多くの同期オブジェクトが浮かんでいるように感じます。
そこで、クラス宣言とサンプル関数を用意して、次の質問をします。これはきめが細かすぎますか? きめが細かすぎませんか?よく考えられていませんか?
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);
}
いくつかの説明: 最初の PoolPtr は、ポインターと、ポインターの元のプール内のセグメント番号を格納するオブジェクトのような愚かな小さなポインターです。
第二に、これはすべて「テンプレート化」されていますが、コードブロックの長さを減らすためにそれらの行を取り出しました
3 番目の ReadWriteLock は、mutex と条件変数のペアを使用してまとめたものです。