如何仅用compare_and_swap实现优先级锁?

发布于 2024-08-19 13:58:30 字数 161 浏览 1 评论 0原文

仅给出比较和交换,我就知道如何实现锁。

但是,如何实现自旋锁

1)多个线程在尝试锁定时可以阻塞它 2)然后线程按照它们阻塞的顺序解除阻塞(并获取锁)?

有可能吗?如果没有,我还需要什么其他原语?

如果是这样,我该怎么做?

谢谢!

Given only compare and swap, I know how to implement a lock.

However, how do I implement a spin lock

1) multiple threads can block on it while trying to lock
2) and then the threads are un-blocked (and acquire the lock) in the order that they blocked on it?

Is it even possible? If not, what other primitives do I need?

If so, how do I do it?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

や三分注定 2024-08-26 13:58:30

您将需要一个等待线程的列表。您需要以线程安全的方式在列表中添加和删除项目。您需要能够休眠未能获取锁的线程。当锁可用时,您需要能够唤醒 1 个线程。在 Linux 中,您可以通过让线程等待信号来完成睡眠和等待。

现在有一种懒惰的方法可以做到这一点,您可能不需要关心唤醒线程。这是我们的跳跃列表的伪代码。这就是我们添加项目所做的事情。

cFails = 0
while (1) {
  NewState = OldState = State;
  if (cFails > 3 || OldState.Lock) {
    sleep();  // not too sophisticated, because they cant be awoken
    cFails = 0;
    continue;
  }

  Look for item in skiplist
  return item if we found it

  // to add the item to the list we need to lock it

  // ABA lock uses a version number
  NewState.Lock=1;
  NewState.nVer++;
  if (!CAS(&State,OldState, NewState)) {
    ++cFails;
    continue; 
  }

  // if the thread gets preempted right here, the lock is left on, and other threads
  // spinning would waste their entire time slice.

  // unlock
  OldState = NewState;
  NewState.Lock = 0;
  NewState.nVer++;
  CAS(&State, OldState,NewState);  
}

我们期望跳跃列表通常能够找到该项目,并且很少需要添加它。即使有很多线程,我们也很少需要添加竞争。我们使用最坏的情况对此进行了测试,其中包括大量线程向单个列表添加和搜索数百万个项目。结果是我们很少看到线程无法获得锁。因此,对于预期情况而言高性能的简单方法对我们来说很有效。可能会发生一件坏事 - 持有锁的线程被抢占。那就是 cFails > 的时候3 捕捉到这个并让等待线程休眠,这样我们就不会浪费它们的时间片进行一百万次无用的旋转。因此,cFails 设置得足够高,以使其检测到锁的所有者不处于活动状态。

You are going to need a list for the waiting threads. You need to add and remove items from the list in a thread safe manner. You will need to be able to sleep threads that fail to acquire the lock. You will need to be able to wake 1 thread when the lock becomes available. In linux you can accomplish the sleep and wait thing by having the thread wait on a signal.

Now there is a lazy way to do this, you might not need to care about waking threads. Here is pseudo code for our skiplist. This is what we do to add an item.

cFails = 0
while (1) {
  NewState = OldState = State;
  if (cFails > 3 || OldState.Lock) {
    sleep();  // not too sophisticated, because they cant be awoken
    cFails = 0;
    continue;
  }

  Look for item in skiplist
  return item if we found it

  // to add the item to the list we need to lock it

  // ABA lock uses a version number
  NewState.Lock=1;
  NewState.nVer++;
  if (!CAS(&State,OldState, NewState)) {
    ++cFails;
    continue; 
  }

  // if the thread gets preempted right here, the lock is left on, and other threads
  // spinning would waste their entire time slice.

  // unlock
  OldState = NewState;
  NewState.Lock = 0;
  NewState.nVer++;
  CAS(&State, OldState,NewState);  
}

We expect the skiplist to usually find the item and only rarely have to add it. We rarely have a race to add, even with a lot of threads. We tested this with a worst case scenario consisting of lots of threads adding and searching for millions of items to a single list. The result is we rarely saw threads fail to get the lock. So the simple approach that is high performance for the expected case works for us. There is one bad thing that can happen - a thread gets preempted holding the lock. Thats when cFails > 3 catches this and sleeps waiting threads so we don't waste their timeslices with a million useless spins. So cFails is set high enough that it detects that the owner of the lock is not active.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文