结构的互锁交换

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 函数,如果可以足够快地获得所有权,则该函数不会等待锁定。

【讨论】:

以上是关于结构的互锁交换的主要内容,如果未能解决你的问题,请参考以下文章

Win32 上的互锁操作与 XXX::atomic

SQL Server Profiler 中的死锁图显示同一集群键上的互锁

JSON基础

JSON基础

JSON字符串和java对象的互转

转载-------- JSON 与 对象 集合 之间的转换 JSON字符串和java对象的互转json-lib