3

回到我作为 BeOS 程序员的日子里,我读了 Benoit Schillings 的这篇文章,描述了如何创建一个“Benaphore”:一种使用原子变量来强制执行关键部分的方法,从而避免了在常见的情况下获取/释放互斥锁的需要(无争用)情况。

我认为这相当聪明,而且您似乎可以在任何支持原子增量/减量的平台上执行相同的技巧。

另一方面,这看起来可以很容易地包含在标准互斥锁实现本身中......在这种情况下,在我的程序中实现这个逻辑将是多余的并且不会提供任何好处。

有谁知道现代锁定 API(例如 pthread_mutex_lock()/pthread_mutex_unlock())是否在内部使用这个技巧?如果没有,为什么不呢?

4

2 回答 2

2

您的文章描述的内容在今天很常见。大多数情况下,它被称为“关键部分”,它由一个互锁变量、一堆标志和一个内部同步对象(互斥锁,如果我没记错的话)组成。一般来说,在争用较少的场景中,Critical Section 完全在用户态执行,不涉及内核同步对象。这保证了快速执行。当争用高时,内核对象用于等待,释放时间片导电以加快周转速度。

一般来说,在这个时代实现同步原语几乎没有意义。操作系统带有各种各样的此类对象,并且它们在比单个程序员想象的更广泛的场景中进行了优化和测试。发明、实施和测试一个好的同步机制实际上需要数年时间。这并不是说尝试没有价值:)

于 2009-10-28T07:19:12.140 回答
0

Java AbstractQueuedSynchronizer(及其兄弟AbstractQueuedLongSynchronizer)的工作方式类似,或者至少可以类似地实现。这些类型构成了 Java 库中几个并发原语的基础,例如ReentrantLockFutureTask

它通过使用原子整数来表示状态来工作。锁可以将值 0 定义为未锁定,将 1 定义为锁定。任何希望获得锁的线程都会尝试通过原子比较和设置操作将锁状态从 0 更改为 1;如果尝试失败,则当前状态不为 0,这意味着锁由其他线程拥有。

AbstractQueuedSynchronizer还通过维护CLH 队列来促进锁的等待和条件通知,CLH 队列是无锁链表,表示等待获取锁或通过条件接收通知的线程行。这样的通知将一个或所有等待条件的线程移动到等待获取相关锁的队列的头部。

大多数这种机制可以用一个表示状态的原子整数以及每个等待队列的几个原子指针来实现。哪些线程将竞争检查和更改状态变量(例如,通过AbstractQueuedSynchronizer#tryAcquire(int))的实际调度超出了此类库的范围,并且属于主机系统的调度程序。

于 2009-12-07T01:09:52.600 回答