【发布时间】:2014-01-16 14:31:34
【问题描述】:
我有一个这样的结构:
struct Chunk
{
private:
public:
Chunk* mParent;
Chunk* mSubLevels;
Int16 mDepth;
Int16 mIndex;
Reference<ValueType> mFirstItem;
Reference<ValueType> mLastItem;
public:
Chunk()
{
mSubLevels = nullptr;
mFirstItem = nullptr;
mLastItem = nullptr;
}
~Chunk() {}
};
chunk 中的mSubLevels 在首次访问之前为空。在第一次访问mSubLevels 时,我为mSubLevels 创建一个chunks 数组并填充其他成员。但是因为多个线程与chunks 一起工作,所以我使用mutex 执行此过程。所以创建新的chunks 受到mutex 的保护。在这个过程之后没有写入这个chunks 并且它们是只读数据,所以线程访问这个chunks 而没有任何mutex。
确实,我有一些方法,在其中一个方法中,在第一次访问mSubLevels 时,我检查这个指针,如果它为空,我将通过mutex 创建所需的数据。但其他方法是只读的,我不会更改structure。所以我在这个函数中不使用任何mutex。 (在创建chunks 的线程和读取它们的线程之间没有任何acquire/release 排序)。
现在我可以使用常规数据类型,还是必须使用atomic 类型?
编辑 2:
为了创建数据我使用double checked locking:
(这是一个将创建新的chunks的函数)
Chunk* lTargetChunk = ...;
if (!std::atomic_load(lTargetChunk->mSubLevels, std::memory_order_relaxed))
{
std::lock_guard lGaurd(mMutex);
if (!std::atomic_load(lTargetChunk->mSubLevels, std::memory_order_relaxed))
{
Chunk* lChunks = new Chunk[mLevelSizes[l]];
for (UINT32 i = 0; i < mLevelSizes[l]; ++i)
{
Chunk* lCurrentChunk = &lChunks[i];
lCurrentChunk->mParent = lTargetChunk;
lCurrentChunk->mDepth = lDepth - 1;
lCurrentChunk->mIndex = i;
st::atomic_store(lCurrentChunk->mSubLevels, (Chunk*)bcNULL, memory_order_relaxed);
}
bcAtomicOperation::bcAtomicStore(lTargetChunk->mSubLevels, lChunks, std::memory_order_release);
}
}
暂时,想象一下我对mSubLevels 不使用原子操作。
我还有一些其他方法只能读取这个chunks 而没有任何“互斥锁”:
bcInline Chunk* _getSuccessorChunk(const Chunk* pChunk)
{
// If pChunk->mSubLevels isn't null do this operation.
const Chunk* lChunk = &pChunk->mSubLevels[0];
Chunk* lNextChunk;
if (lChunk->mIndex != mLevelSizes[lChunk->mDepth] - 1)
{
lNextChunk = lChunk + 1;
return lNextChunk;
}
else ...
如您所见,我可以访问mSubLevels、mIndex 和其他一些。在此函数中,我不使用任何“互斥锁”,因此如果编写器线程不将其缓存刷新到主内存,则将运行此函数的任何线程都不会看到受影响的更改。如果我在这个函数中使用mMutex,我认为问题将得到解决。 (写入器线程和读取器线程将通过互斥锁中的原子操作同步)现在,如果我在第一个函数中使用 mSubLevels 的原子操作(如我所写)并使用“获取”在第二个函数中加载它:
bcInline Chunk* _getSuccessorChunk(const Chunk* pChunk)
{
// If pChunk->mSubLevels isn't null do this operation.
const Chunk* lChunk = &std::atomic_load(pChunk->mSubLevels, std::memory_order_acquire)[0];
Chunk* lNextChunk;
if (lChunk->mIndex != mLevelSizes[lChunk->mDepth] - 1)
{
lNextChunk = lChunk + 1;
return lNextChunk;
}
else ...
读取线程将看到写入线程的更改,不会发生cache coherence 问题。这句话是真的吗?
【问题讨论】:
-
我的问题是
cache coherency
标签: c++ multithreading mutex atomic