gpt4 book ai didi

c++ - 无法让 std::atomic 正确保护数据

转载 作者:行者123 更新时间:2023-11-30 02:34:50 26 4
gpt4 key购买 nike

为什么 std::atomic 版本的代码仍然失败? (当 refCount 为非零且 doStop(为)false 时回调发生变化。

我有一段多线程代码,它的行为不正确,并试图修复它。

但是我的修复仍然不可靠,但我不明白为什么。

原代码线程A(使用回调):-

 if( !IsUpdating ) {
IncrementReference();
if( !IsUpdating && GetCallBackPointer() ) {
cb = GetCallBackPointer();
cb();
}
DecrementReference();
}

原代码线程B-(修改回调)

 IsUpdating = true;
while( ReferencesUsingCallback ) {
Sleep( 10 );
}
callback = newValue;
IsUpdating = false;

想法是,如果 ReferencesUsingCallback 不为​​ 0,则不允许修改回调线程更改回调的值。

通过测试、AddRef 和测试可以“保护”竞争条件。希望测试不要再失败。

不幸的是代码没有工作,我的假设是这是由于一些缓存一致性问题。

我已经使用 std::atomic 尝试再次交付测试用例,但它仍然会失败。 std::atomic 版本是“AtomicLockedData”。平台是 Windows on Intel i7

完整代码:-

#include <thread>
#include <mutex>
#include <atomic>
#include <chrono>

#define FAILED_LIMIT 5
#define LOOP_SIZE 1000000000LL

void Function()
{
}
typedef void (*CallbackFunction)(void);


int FailedCount;
__int64 counter = 0;
class lockedData {
public:
lockedData() : value(nullptr), value2(nullptr)
{
doStop = 0;
usageCount = 0;
}
long usageCount;
long doStop;
volatile CallbackFunction value;
void * value2;
int Use()
{
return usageCount++;
}
int UnUse()
{
return usageCount--;
}
int Usage() const
{
return usageCount;
}
void SetStop()
{
doStop = 1;
}
void UnStop()
{
doStop = 0;
}
bool IsStopped()
{
return doStop != 0;
}
void StoreData(CallbackFunction pData )
{
value = pData;
}
CallbackFunction ReadData()
{
return value;
}
};


class AtomicLockedData {
public:
AtomicLockedData() : value(nullptr), value2(nullptr)
{
doStop = false;
usageCount = 0;
}
std::atomic<int> usageCount;
std::atomic<bool> doStop;
std::atomic<CallbackFunction> value;
void * value2;
int Use()
{
return usageCount++;
}
int UnUse()
{
return usageCount--;
}
int Usage() const
{
return usageCount.load();
}
void SetStop()
{
doStop.store( true);
}
void UnStop()
{
doStop.store( false );
}
bool IsStopped()
{
return doStop.load() == true;
}
void StoreData(CallbackFunction pData)
{
value.store( pData );
}
CallbackFunction ReadData()
{
return value.load();
}
};



template < class lockData >
int UpdateState( lockData & aLock, CallbackFunction pData, void * pData2 )
{
aLock.SetStop();
while(aLock.Usage() > 0 )
std::this_thread::sleep_for( std::chrono::milliseconds(10) );

aLock.value = pData;
aLock.UnStop();
return 0;
}

template <class lockData >
int ReadState( lockData * aLock, int fib)
{
if (!aLock->IsStopped()) {
aLock->Use();
CallbackFunction val = aLock->ReadData();
if (!aLock->IsStopped() && val) {
fibonacci(fib);
CallbackFunction pTest = const_cast<CallbackFunction>( aLock->ReadData());
if (pTest == 0) {
FailedCount++; // shouldn't be able to change value if use count is non-zero
printf("Failed\n");
}
else {
pTest();
}
}
aLock->UnUse();
}
return 0;
}

unsigned __int64 fibonacci(size_t n)
{
if (n < 3) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}

template< class lockData > void ThreadA( lockData * lkData , int fib )
{
void * pData2 = new char[200];
while (FailedCount < FAILED_LIMIT) {
UpdateState< lockData>(*lkData, Function, pData2);
fibonacci(fib);
UpdateState< lockData>(*lkData, NULL, NULL);
fibonacci(fib);

}
}

template< class lockData > void ThreadB(lockData & lkData, int fib )
{
while (FailedCount < FAILED_LIMIT && counter < LOOP_SIZE) {
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
ReadState(&lkData, fib);
counter++;
}
}

template <class lockType >
void TestLock()
{
counter = 0;
FailedCount = 0;
lockType lk;
std::thread thr(ThreadA<lockType>, &lk, 3);
ThreadB(lk, 3);
thr.join();
printf("Failed %d times for %I64d iterations", FailedCount, counter);

}
int main(int argc, char ** argv)
{
TestLock< lockedData >();
TestLock< AtomicLockedData >();
return 0;
}

最佳答案

线条

if (!aLock->IsStopped()) {
aLock->Use();

看起来很奇怪。

IsStopped() 返回 false 之后,状态可能会在您调用 Use() 之前变为已停止(因此您可能会得到Use() 一个停止的锁)。

解决方案是使用 Use 的返回值来传达失败,以防它是被禁止的操作,而不是先进行检查,然后再执行 Use()

关于c++ - 无法让 std::atomic 正确保护数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34278426/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com