嗨,我需要在程序的回调函数中使用布尔标志来控制程序行为。回调线程在与设置它们的线程不同的线程中执行。在我的一个回调函数中,程序设置布尔标志,而在另一个回调函数中,它检查不同的不相关的布尔标志。目前我正在使用 std::atomic_bool 来实现此目的。
我读过有关 std::atomic 变量发生死锁的可能性的信息。就我而言,这是值得担心的事情吗?还有什么需要担心的吗?
我在使用atomic_bool像普通变量一样正确地做事吗?如果不是我该怎么办?
我应该使用 std::atomic_flag 来代替吗?
并且编译器在类成员列表中初始化standbyResumeTimerDelayBool时没有抛出错误,不确定这是否正确。
谢谢!
//some code omitted to keep things simple
//first callback function, this boolean flag is checked at one other point in the program
static ULONG Replicator::standbyResumeCallbackFunction(PVOID context, ULONG type, PVOID setting);
ULONG Replicator::standbyResumeCallbackFunction(PVOID context, ULONG type, PVOID setting)
{
if (type == PBT_APMRESUMEAUTOMATIC)
{
Replicator* replicator = reinterpret_cast<Replicator*>(context);
replicator->standbyResumeSetTimerDelayBool();
}
}
//Replicator class members
void standbyResumeSetTimerDelayBool() { standbyResumeTimerDelayBool = true; }
std::atomic_bool standbyResumeTimerDelayBool = false;
//behavior modified here
void Replicator::autoBackup()
{
if (standbyResumeTimerDelayBool)
{
standbyResumeTimerDelayBool = false;
//do stuff
}
}
//second callback function
static DWORD CALLBACK copyProgress(
LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
LPVOID data);
DWORD Worker::copyProgress(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred, LARGE_INTEGER, LARGE_INTEGER, DWORD, DWORD, HANDLE, HANDLE, LPVOID data)
{
Worker *worker = static_cast<Worker *>(data);
if (worker->getStop())
return PROGRESS_CANCEL;
}
//Worker class members
bool getStop() { return cancel; }
std::atomic_bool cancel;
//cancel is set to false when backup begins
void Worker::startBackup()
{
cancel = false;
}
//if user clicks cancel button cancel flag is set to false
void stop() { cancel = true; }
我读过有关 std::atomic 变量发生死锁的可能性的信息。就我而言,这是值得担心的事情吗?
std::atomic
本身永远不会陷入僵局。
我在使用atomic_bool像普通变量一样正确做事吗?
是的,这就是
std::atomic
的重点,让使用原子就像使用普通变量一样简单。
我应该使用 std::atomic_flag 来代替吗?
为什么?
std::atomic_flag
有一个比std::atomic_bool
更复杂的接口,并且检查速度更慢,因为它只能通过RMW操作来检查,它被用作互斥体的构建块,而不是作为原子布尔值。
我唯一有效的评论是在这一行。
if (standbyResumeTimerDelayBool)
{
standbyResumeTimerDelayBool = false;
//do stuff
}
如果有多个线程同时执行此操作,则可能有多个线程最终执行此块,而您应该在此处进行交换
if (standbyResumeTimerDelayBool && !standbyResumeTimerDelayBool.exchange(true))
{
// only 1 thread can enter this block
}
但请注意,此交换比正常写入慢,因此如果只允许 1 个线程执行此代码,那么您的原始代码就可以了。