我正在寻找现实世界中需要在并发系统中对同一值进行读写访问的示例。

在我看来,由于没有已知的替代方法(实现者),因此存在许多信号灯或锁,但是您是否知道似乎需要互斥锁的任何模式?

从某种意义上说,我是在寻找现实世界中并发软件的标准HARD问题集的候选人。

最佳答案

使用哪种类型的锁取决于多个线程如何访问数据。如果您可以微调用例,则有时可以完全消除对排他锁的需求。

仅当您的用例要求共享数据必须始终精确到100%时,才需要排他锁。这是大多数开发人员开始使用的默认设置,因为这就是我们通常对数据的看法。

但是,如果您使用数据的目的是可以忍受的“松散”,则有几种技术可以在线程之间共享数据,而无需在每次访问时都使用互斥锁。

例如,如果您有一个数据链表,并且您对链表的使用不会因在列表遍历中多次看到同一个节点而感到不适,并且如果在插入后没有立即看到一个插入,也不会令您感到不适(或类似的工件),您可以使用原子指针交换执行列表插入和删除,而无需在插入或删除操作周围使用完全停止的互斥锁。

另一个例子:如果您有一个数组或列表对象,大多数情况下是由线程读取的,而偶尔由主线程更新,则可以通过维护列表的两个副本来实现无锁更新:一个副本是“实时的”,另一个副本是“实时的”线程可以从中读取信息,也可以从另一个线程中读取信息,而您可以在自己的线程中进行私密写入。要执行更新,请将“ Activity ”列表的内容复制到“脱机”列表中,执行对脱机列表的更新,然后使用原子指针交换将脱机列表指针交换到 Activity 列表指针中。然后,您将需要某种机制来使读者从现在的脱机列表中“流失”。在垃圾回收系统中,您可以仅释放对脱机列表的引用-当最后一个使用者完成后,将对其进行GC处理。在非GC系统中,您可以使用引用计数来跟踪仍在使用该列表的读者数量。对于此示例,仅将一个线程指定为列表更新器将是理想的。如果需要多个更新程序,则将需要对更新操作进行锁定,而仅是序列化更新程序-不锁定,并且不影响列表的读取器。

我知道的所有无锁资源共享技术都需要使用原子交换(也称为InterlockedExchange)。这通常会在很短的时间内转化为CPU和/或硬件总线锁定(x86汇编器中读取或写入操作码的锁定前缀)中的特定指令。在多进程系统上,原子交换可能会迫使其他处理器上的缓存失效(在双进程Pentium II中就是这种情况),但我认为这在当前的多核芯片上没有太大的问题。即使有这些性能警告,但无锁运行仍比采用完全停止的内核事件对象要快得多。仅调用内核API函数就需要数百个时钟周期(切换到内核模式)。

真实场景的示例:

  • 生产者/消费者工作流程。 Web服务接收http的数据请求,将请求放入内部队列,辅助线程从队列中拉出工作项并执行工作。队列是可读写的,必须是线程安全的。
  • 具有所有权更改的线程之间共享的数据。线程1分配一个对象,将其扔给线程2进行处理,再也不想看到它了。线程2负责处置对象。内存管理系统(malloc/free)必须是线程安全的。
  • 文件系统。这几乎始终是一项OS服务,并且已经完全具有线程安全性,但是值得将其包括在列表中。
  • 引用计数。当引用数降至零时释放资源。递增/递减/测试操作必须是线程安全的。这些通常可以使用原子原语而不是句号的内核互斥锁来实现。
  • 10-03 00:37