Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 我的自旋锁实现正确且最优吗?_C_Multithreading_Concurrency_Mutual Exclusion_Spinlock - Fatal编程技术网

C 我的自旋锁实现正确且最优吗?

C 我的自旋锁实现正确且最优吗?,c,multithreading,concurrency,mutual-exclusion,spinlock,C,Multithreading,Concurrency,Mutual Exclusion,Spinlock,我用旋转锁来保护一个非常小的关键部分。争用很少发生,因此自旋锁比常规互斥锁更合适 我当前的代码如下所示,并假定为x86和GCC: volatile int exclusion = 0; void lock() { while (__sync_lock_test_and_set(&exclusion, 1)) { // Do nothing. This GCC builtin instruction // ensures memory barrie

我用旋转锁来保护一个非常小的关键部分。争用很少发生,因此自旋锁比常规互斥锁更合适

我当前的代码如下所示,并假定为x86和GCC:

volatile int exclusion = 0;

void lock() {
    while (__sync_lock_test_and_set(&exclusion, 1)) {
        // Do nothing. This GCC builtin instruction
        // ensures memory barrier.
    }
}

void unlock() {
    __sync_synchronize(); // Memory barrier.
    exclusion = 0;
}
所以我想知道:

* Is it correct?
  • 这个代码正确吗?它是否正确地确保了相互排斥
  • 它能在所有x86操作系统上工作吗
  • 它也适用于x86_64吗?在所有操作系统上
  • 它是最优的吗?
    • 我见过使用比较和交换的自旋锁实现,但我不确定哪个更好
    • 根据GCC原子内置文档(),还有
      \uuuu同步\uu锁定\uu释放
      。我不是记忆障碍方面的专家,所以我不确定是否可以用它来代替
      \uuuu sync\u synchronize
    • 我正在为没有争用的情况进行优化

我一点也不在乎争论。每隔几天可能会有1到2个其他线程尝试锁定自旋锁。

回答您的问题:

  • 我觉得还可以
  • 假设操作系统支持GCC(并且GCC已经实现了功能);这应该适用于所有x86操作系统。GCC文档表明,如果给定平台不支持,将生成警告
  • 这里没有x86-64的具体内容,所以我不明白为什么不。这可以扩展到GCC支持的任何体系结构,但是在非x86体系结构上可能有更好的实现方法
  • unlock()
    案例中使用
    \u sync\u lock\u release()
    可能会稍微好一点;因为这将在一次操作中减少锁并添加内存屏障。然而,假设你的断言很少会有争论;我觉得不错

  • 我不能对正确性发表评论,但在我阅读问题正文之前,你问题的标题就已经引起了我的注意。同步原语很难保证正确性。。。如果可能的话,最好使用设计良好/维护良好的库,或者。

    一个改进建议是使用(test和test并设置)。使用CAS操作对于处理器来说是非常昂贵的,因此如果可能,最好避免使用CAS操作。
    另一件事,确保您不会遭受优先级反转的影响(如果高优先级线程尝试获取锁,而低优先级线程尝试释放锁,该怎么办?例如,在Windows上,调度程序使用优先级提升最终会解决此问题,但如果在过去20次尝试中未成功获取锁,您可以显式放弃线程的时间片。)(例如…)

    在我看来很好。顺便说一句,这里的实现即使在有争议的情况下也更有效

    void lock(volatile int *exclusion)
    {
        while (__sync_lock_test_and_set(exclusion, 1))
            while (*exclusion)
                ;
    }
    

    您的解锁过程不需要内存屏障;只要在x86上dword对齐,对排除的分配就是原子的。

    如果您使用的是最新版本的Linux,则可以使用--a“快速用户空间互斥”:

    正确编程的futex锁将不会使用系统调用,除非该锁处于争用状态

    在无争议的情况下,您正试图使用自旋锁对其进行优化,futex将像自旋锁一样运行,而不需要内核系统调用。如果锁有争议,等待将在内核中进行,而不需要忙着等待。

    所以我想:

    * Is it correct?
    
    在上述情况下,我想说是的

    * Is it optimal?
    
    这是一个复杂的问题。通过重新发明轮子,你也重新发明了许多其他实现已经解决的问题

    • 如果您不尝试访问锁字,则可能会在失败时出现浪费循环

    • 在解锁中使用完整的屏障只需要具有释放语义(这就是为什么您要使用uu sync_lock_release,这样您就可以在安腾上获得st1.rel而不是mf,或者在powerpc上获得lwsync等)。如果您真的只关心x86或x86 64,那么这里使用的屏障类型与否并不重要(但如果你想在哪里使用英特尔安腾的HP-IPF端口,你就不会想要这个)

    • 您没有通常放在废物循环之前的pause()指令

    • 当有争论时,你想要一些东西,semop,甚至是绝望中的一个愚蠢的睡眠。如果你真的需要这为你带来的性能,那么futex建议可能是一个好建议。如果你需要这为你带来的性能差到足以维护这段代码,你有很多研究要做

    请注意,有一条评论说不需要释放屏障。即使在x86上也不是这样,因为释放屏障还可以作为一条指令,指示编译器不要在“屏障”周围洗牌其他内存访问。这与使用asm(“:“内存”)时得到的结果非常相似


    在x86上,sync_lock_test_和_集将映射到一个带有隐含锁前缀的xchg指令。绝对是生成的最紧凑的代码(特别是如果您使用一个字节作为“锁字”而不是int),但其正确性不亚于使用lock CMPXCHG。比较和交换可以用于更高级的算法(比如在失败时将指向第一个“服务员”元数据的非零指针放入锁字中)。

    我想知道以下CAS实现是否是x86_64上的正确实现。 在我的i7 X920笔记本电脑(fedora 13 x86_64,gcc 4.4.5)上,速度几乎快了一倍


    在x86(32/64)的特定情况下我认为在解锁代码中根本不需要内存隔离。x86不进行任何重新排序,只是存储首先放在存储缓冲区中,因此其他线程可以延迟它们的可见。如果一个线程进行存储,然后从同一个变量中读取,那么如果它尚未刷新到mem中,它将从其存储缓冲区中读取或
    inline void lock(volatile int *locked) {
        while (__sync_val_compare_and_swap(locked, 0, 1));
        asm volatile("lfence" ::: "memory");
    }
    inline void unlock(volatile int *locked) {
        *locked=0;
        asm volatile("sfence" ::: "memory");
    }