我对人们用来发布信息和更改数据结构的技术感兴趣,这些数据结构在多个线程中共享而不会丢失很多并发性。根据我的个人经验,我经常遇到单个编写器/多个读者,其中单个线程正在更新对象,但是多个线程正在从对象读取并需要了解更改。
作为一个简单的例子,考虑一个哈希表(让我们假设它是线程安全的,无论是通过粗粒度锁定,细粒度锁定还是低锁技术等)。线程1负责从哈希表中添加和删除信息,但是唯一的编写者。当任何密钥被更改,某个密钥被更改或任何变体时,可能希望通知其他线程。他们希望订阅的内容并不是特别重要。
您会使用哪些技巧(我喜欢论文的建议)来确保线程及时获得正确的更改信息?
答案 0 :(得分:1)
执行此操作的经典方法是使用等待条件,但它们会阻塞线程直到事件到达。
如今,我将为每个工作线程使用一个消息队列,对中央数据结构的更新将是发布到工作线程队列中的消息。这也是内部使用等待条件,但它是一个比裸等待条件更高级别的接口,并且几乎所有编程语言都有很好的库支持。
一个更为hackish的解决方案是在套接字上的select()
调用上阻塞线程,通知线程写入一个字节来唤醒休眠线程。使用select()
的优点是,您可以将此类事件与几乎所有其他事件处理进行复用,因此当目标线程例如是GUI线程。
答案 1 :(得分:1)
你实际上已经问过两个不同的问题
MultipleReader / SingleWriter排除
更新通知(通常称为观察者模式)
MultipleReader / SingleWriter Locks是一个CLASSIC问题,其中有大量文献。真正的问题是许多经典解决方案涉及多个互斥锁和信号量,并且可能非常重量级,每个简单的写锁定需要6个读取修改写入(RMW)周期,第一个读取锁定需要6个RMW
这两个问题有很多解决方案,其效率和实用性取决于读取的到达率,写入的到达率,写入的持续时间,读取的持续时间,是否可以批量更新,是否需要升级读锁定,降级写锁定(在你的情况下听起来没有)
对于哈希表的示例,您可以使用“O(n访问线程)的中等粒度锁定,并且只是将锁定任意地分配给哈希表的块(单独链接注意到你。使用开放寻址锁定不会必须锁定被探测到的插槽)。或者你也可以使用hop-scotch哈希并发哈希表算法
就通知而言,一些典型的问题是:
每个读取线程都必须查看(并处理)每个通知吗? 观察者是静态的还是动态的?即通知“网络”是否可以是静态的(编译时定义)