我使用互斥锁来锁定和解锁变量,因为我在更新周期中不断地从主线程调用 getter 并从另一个线程调用 setter。我在下面提供了 setter 和 getter 的代码
定义
bool _flag;
System::Mutex m_flag;
通话
#define LOCK(MUTEX_VAR) MUTEX_VAR.Lock();
#define UNLOCK(MUTEX_VAR) MUTEX_VAR.Unlock();
void LoadingScreen::SetFlag(bool value)
{
LOCK(m_flag);
_flag = value;
UNLOCK(m_flag);
}
bool LoadingScreen::GetFlag()
{
LOCK(m_flag);
bool value = _flag;
UNLOCK(m_flag);
return value;
}
这在一半情况下工作得很好,但有时变量在调用 SetFlag 时被锁定,因此它永远不会被设置,从而扰乱代码流。
谁能告诉我如何解决这个问题?
编辑:
这是我最终采用的解决方法。这只是一个临时解决方案。如果有人有更好的答案,请告诉我。
bool _flag;
bool accessingFlag = false;
void LoadingScreen::SetFlag(bool value)
{
if(!accessingFlag)
{
_flag = value;
}
}
bool LoadingScreen::GetFlag()
{
accessingFlag = true;
bool value = _flag;
accessingFlag = false;
return value;
}
最佳答案
您遇到的问题(user1192878 暗示)是由于编译器加载/存储延迟所致。您需要使用 memory barriers实现代码。您可以声明 volatile bool _flag;
.但这不需要 compiler memory barriers对于单 CPU 系统。多 CPU 解决方案需要硬件障碍(在维基百科链接下方);硬件屏障确保所有 CPU 都能看到本地处理器的内存/缓存。 mutex
的使用在这种情况下不需要其他互锁。他们究竟完成了什么?它们只会造成死锁,并不需要。
bool _flag;
#define memory_barrier __asm__ __volatile__ ("" ::: "memory") /* GCC */
void LoadingScreen::SetFlag(bool value)
{
_flag = value;
memory_barrier(); /* Ensure write happens immediately, even for in-lines */
}
bool LoadingScreen::GetFlag()
{
bool value = _flag;
memory_barrier(); /* Ensure read happens immediately, even for in-lines */
return value;
}
只有在同时设置多个值时才需要互斥锁。您也可以更改 bool
输入 sig_atomic_t或 LLVM atomics .然而,这是相当迂腐的 bool
将适用于大多数实际的 CPU 架构。 Cocoa's concurrency pages也有一些关于替代 API 的信息来做同样的事情。我相信 gcc 的内联汇编器 与 Apple 的编译器使用的语法相同;但这可能是错误的。
API 有一些限制。实例 GetFlag()
返回,有事可调用SetFlag()
. GetFlag()
返回值就过时了。如果您有多位作家,那么您很容易错过一位 SetFlag()
.如果更高级别的逻辑容易出现 ABA problems,这可能很重要.但是,所有这些问题在有/没有互斥量的情况下都存在。 内存屏障 仅解决编译器/CPU 不会缓存 SetFlag()
的问题很长一段时间,它会重新读取 GetFlag()
中的值.声明 volatile bool flag
通常会导致相同的行为,但会产生额外的副作用,并且不会解决多 CPU 问题。
std::atomic<bool>
根据 stefan 和 atomic_set(&accessing_flag, true);
通常会在他们的实现中做与上面描述的相同的事情。如果它们在您的平台上可用,您可能希望使用它们。
关于c++ - 互斥锁未解锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15115703/