【发布时间】:2010-12-30 22:23:26
【问题描述】:
假设我有一个函数尝试使用此代码保护全局计数器:
static MyCriticalSectionWrapper lock;
lock.Enter();
counter = ++m_counter;
lock.Leave();
两个线程是否有可能调用lock 的构造函数?实现这一目标的安全方法是什么?
【问题讨论】:
标签: c++
假设我有一个函数尝试使用此代码保护全局计数器:
static MyCriticalSectionWrapper lock;
lock.Enter();
counter = ++m_counter;
lock.Leave();
两个线程是否有可能调用lock 的构造函数?实现这一目标的安全方法是什么?
【问题讨论】:
标签: c++
锁对象本身的创建不是线程安全的。根据编译器的不同,如果多个线程(几乎)同时进入函数,您可能会创建多个独立的锁对象。
这个问题的解决方法是使用:
【讨论】:
构造函数调用可以依赖于实现和/或执行环境,但这不是 scoped_lock 所以不是问题。
我认为主要操作被适当地防止了多线程访问。
(你知道,全局对全局,函数静态对函数静态。该锁变量必须与受保护对象在同一范围内定义。)
【讨论】:
原始示例代码:
static MyCriticalSectionWrapper lock;
lock.Enter();
counter = ++m_counter;
lock.Leave();
我意识到计数器代码可能只是一个占位符,但是如果它实际上是您尝试做的,您可以使用 Windows 函数“InterlockedIncrement()”来完成此操作。 示例:
// atomic increment for thread safety
InterlockedIncrement(&m_counter);
counter = m_counter;
【讨论】:
这取决于你的锁实现。
【讨论】:
lock 是一个静态块范围变量。 (当前)标准的第 [6.7] 节第 4 段说“这样的对象在控制第一次通过其声明时被初始化”。 stackoverflow.com/questions/898432/… 涵盖了 C++ 编译器是如何做到这一点的。它不是线程安全的,因此多个线程可以同时运行MyCriticalSectionWrapper 构造函数,使其处于未定义状态。不过,对于基于最新草案 n3126 的 C++0x,您的说法是正确的。
lock 不是锁对象,而是临界区实例本身。这是一个不幸的命名,因为 lock 应该被命名为 sync_object 或类似的名称。其他人担心的是,关键部分或互斥对象在首先正确创建之前无法锁定。