我使用旋锁,以保护一个非常小的关键部分。争会发生 非常 很少这样一个旋锁更适合于一个经常互斥。

我目前的代码如下,并假定x86和海湾合作委员会:

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;
}

所以我想知道:

  • 这是代码是否正确?不是正确的保证相互排斥?
  • 它的工作在所有x86操作系统?
  • 它的工作在x86_64吗?在所有操作系统?
  • 它是最佳的?
    • 我见过旋转锁的实施使用比较和交换但我不知道哪个更好。
    • 根据海湾合作委员会内置的原子文件(http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html)还有 __sync_lock_release.我不是专家在内存障碍,所以我不确定它是否是我使用这个代替 __sync_synchronize.
    • 我是优化的情况没有争议。

我不在乎 在所有 关于竞争。可能有1,也许2其他线试图锁旋锁一次每隔几个 .

有帮助吗?

解决方案

所以我想知道:

* Is it correct?

在该上下文中所提到的,我会说是的。

* Is it optimal?

这是一个装载的问题。通过重新发明轮子,你也是重新塑造一个很大的问题已经解决,由其它实现

  • 我期望一个废物循环上的失败,你没有试图访问锁字。

  • 使用一个充满障碍的解锁只需要有释义(这就是为什么你会用__同步_锁_释放,这样,你会得到st1。rel上处理,而不是mf,或lwsync上的支持,...).如果你真的只关心x86或x86_64的种类型的障碍,在这里使用或不不论多(但如果你在那里跳到英特尔公司的处理的一HP-森林小组口然后你不会想这)。

  • 你没有暂停()指令,你通常会之前,把你的废物的循环。

  • 当没争你想要的 的东西,semop,或者甚至一个愚蠢的睡眠中的绝望。如果你真的需要的性能,这个给你然后futex建议可能是一个很好的一个。如果你需要的性能,这个给你买够糟糕 维持 这个代码你有很多研究要做。

注意,有一个评论说,释放屏障是不是必需的。那不是真实的,即使在x86因为释放的障碍也可作为一个指令来编译器不是随机的其他存储在访问周围的"壁垒"。非常喜欢的你会得到什么如果你使用 asm ("":::"记忆").

* on compare and swap

在x86的sync_lock_test_and_set将线图xchg指示其有一个隐含的锁定的前缀。绝对的最紧凑产生的代码(esp。如果你使用一个字节的"锁定词语"而不是一个int),但没有那么正确的,比如果你用锁CMPXCHG.使用的比较和交换可用于更好的algorthims(像把一个非零的指针到元数据的第一个"服务员"进入锁定字上的失败)。

其他提示

看起来不错,给我。顺便说一句,这里是的 教科书 执行更有效的即使是在竞争的情况。

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

在回答您的问题:

  1. 看起来确定我
  2. 假设的操作系统支持海湾合作委员会(和海湾合作委员会已经实现的功能);这应该在所有x86操作系统。海湾合作委员会的文件表明,警告会产生如果他们不支持在一定的平台。
  3. 没有什么x86-64具体在这里,所以我不明白为什么不。这可以扩大到涵盖 任何 建筑,海湾合作委员会的支持,但也有可能更多的最佳方式实现这在非x86架构。
  4. 你可能会稍微更好的使用 __sync_lock_release()unlock() 情况;因为这将减少锁,并添加一个记忆阻挡在一个单一的操作。然而,假设你的说法有很少会竞争;它看起来对我很好。

如果你在最近的Linux版本,可能可以使用 futex -一个"快速的用户互斥":

一个正常程futex基锁将不会使用的系统的电话时除外锁是竞争

在无争议的情况下,这你想要优化与你调节锁,futex会表现得就像一个调节锁,而不需要一个内核系统调用.如果锁定提出异议,等待发生核不忙-等待。

我不知道,如果下列CAS实施是正确的上x86_64.这几乎是两倍,速度更快我i7X920笔记本电脑(fedora13x86_64,海湾合作委员会4.4.5).

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");
}

我不能评论的正确性,但标题你的问题提出了一个红色的标志之前,我甚至读问题的身体。同步的原语非常难以保证正确性...如果可能的话,你最好采用一个设计良好的/维持的图书馆,也许 提升::线.

一个改进建议是使用 塔塔 (试验和试验和设置)。使用CAS行动被认为是相当昂贵的处理器,所以它是最好避免他们如果可能的话。另一件事,确保你不会遭受优先权的转(如果有什么线与一个高度优先试图获取锁而一线与低优先试图免费的锁?在Windows例如这个问题最终将通过解决计划程序使用的一个优先提高,但可以明确放弃你的纹的时间片种情况下你没有成功获取锁在你去20次尝试(例如..)

你解开的程序并不需要存储器障碍;分配到排斥的原子,只要它双盟在x86。

在特定情况下x86(32/64)我不觉得你需要一个栅栏存在的所有在解锁码。x86没有做任何重新排序,除了储存是第一放在一个存放缓冲区,所以它们变得可见的,可推迟其他的螺纹。和一个线程,并商店然后读取自同一变量将从中读取它的缓冲,如果它还没有被刷新记忆。因此,所有你需要的是一个 asm 声明,以防止编译器reorderings.你冒的风险的一线保持锁定略微超过必要的立的其他线,但是如果你不关心论点,即不应该的问题。事实上, pthread_spin_unlock 实现一样,在我的系统(linux x86_64).

我的系统中也实现了 pthread_spin_lock 使用 lock decl lockvar; jne spinloop; 而不是使用 xchg (这是什么 __sync_lock_test_and_set 采用),但是我不知道,如果有实际性能差异。

有几个错误的假设。

第一,调节锁才有意义,如果资源锁定在另一个CPU。如果资源锁定在相同的CPU(其总的情况在单处理器系统),你需要放松调度程序,以便解ressource.你现代码将单处理器系统,因为调度程序将关的任务自动的,但它浪费的资源.

在多处理系统,同样的事情可以的,但任务可能从一个迁移CPU到另一个。总之,使用的旋转锁是正确的,如果你保证,你的任务将运行在不同的CPU。

其次,锁定一个互斥是快速的(尽快调节锁)当是解锁。互斥锁定(和解锁)是缓慢的(非常缓慢),如果只是互斥已经锁定。

所以,在你的情况下,我建议使用互斥体。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top