结构的互锁交换
Posted
技术标签:
【中文标题】结构的互锁交换【英文标题】:Interlocked Exchange of a struct 【发布时间】:2011-05-24 11:40:01 【问题描述】:我想使用 WinAPI 中的 InterlockedExchange 来使用线程的无锁同步。 目前我有这样的课程。
struct DataExchange
volatile LONG m_value;
void SetValue(LONG newVal)
InterlockedExchange(&m_value, newVal);
LONG GetValue()
LONG workVal=0;
InterlockedExchange(&workVal, m_value);
return workVal;
;
一个线程可以设置一个新值,另一个线程可以读取这个值。
现在我想做的是将LONG
值更改为struct
。
WinAPI中有什么方法可以复制struct
无锁吗?
【问题讨论】:
对变量使用原子访问实际上并不能使其无锁,因为原子访问也是一个非常小的关键部分,尽管是在 CPU 上实现的。 如果你想要无锁、无栅栏,也许你应该考虑这个 URL:calvados.di.unipi.it/dokuwiki/doku.php?id=ffnamespace:about Lockfree 在这种情况下确实是错误的。但这是我可以在 Windows 机器上使用的最快同步。 @sep +1 获取不错的链接。有时间我会去看看 Raymond Chen (The Old New Thing) 上个月就这个话题写了很多文章,例如Lock-free algorithms: The one-time initialization 如果struct
大于 32 位,则不会。但是您可以做的是将 指针 交换到 struct
。
【参考方案1】:
没有,除非您可以将结构调整为 32 位,在这种情况下,您可以继续使用 InterlockedExchange。
【讨论】:
【参考方案2】:您可以在 64 位平台和 Windows Vista/7 上使用 InterlockedExchange64 对 64 位值进行原子操作。这足以在一个结构中容纳两个 32 位 int
值。
由于该函数是使用编译器内部实现的,因此它基本上是在 x86 上调用与平台相关的汇编指令,例如 CMPXCHG
。由于该指令最多只能在 64 位寄存器源操作数、64 位寄存器或内存目标操作数以及RAX
寄存器上工作(在 64 位平台上),因此您只有一个特定大小的值可以使用单个汇编指令执行原子操作,而无需结合某种类型的锁或信号量来创建临界区。
【讨论】:
【参考方案3】:仅当结构正好是 32 位时。
另一种方法是在指向结构的指针上使用 InterlockedExchange。结构必须是不可变的(或永远不会改变它)。要更新结构,请创建一个新结构,然后交换指针。您必须小心销毁结构,以确保它只执行一次,并且只有在没有人使用它的情况下。
【讨论】:
@lou-franco:但是在这种情况下,使用 new 和 delete 将与我的目标背道而驰。因为堆管理器也会做一些内部锁定。 @mkaes:你测量过吗?不要忽略一个潜在的方法,因为它可能会表现出某些行为——你应该检查一下。 (我还建议在对您的问题的评论中使用指针,我认为这值得您调查。)【参考方案4】:您可以做的最好的事情是使用InitializeCriticalSectionAndSpinCount
函数,如果可以足够快地获得所有权,则该函数不会等待锁定。
【讨论】:
以上是关于结构的互锁交换的主要内容,如果未能解决你的问题,请参考以下文章