C++,如何为多个线程制作高效的、1 个共享的资源数组

问题描述

说明:

我有多个线程 (4-32)。这些线程都可以访问一个数组:int resources[1024]。 资源数组包含不同的值 (0-1023)。单个资源(int)只能有一个实例。每个线程需要不同数量的资源,这些资源在某个时候返回给数组。线程可以多次请求资源,并且一次只返回获取的部分资源。每个线程都通过 2 个方法访问这个数组:GetElement(),ReturnElement(int element)

GetElement():此方法锁定部分,从资源数组中删除最后一个元素并将其返回给调用线程。每个线程都在为 n 个资源循环调用方法

ReturnElement(int element):此方法锁定部分,在数组中最后一个后附加参数中的资源元素。每个线程都在为 n 个资源循环调用方法

当前的实现方式存在缺陷,即当多个线程同时获取资源时,可能没有一个线程获得所需的数量。我正在考虑在单个线程获取或返回资源时锁定对数组的访问,然后将其解锁。这种方法会阻塞所有其他可能有问题的线程。

有没有更有效的方法

解决方法

这个问题是 dining philosophers problem 的一个变体,这是一个活跃的研究领域。有一些解决方案,但没有一个是完美的,通常在这种情况下,以通用和恒定时间的方式避免死锁是有问题的。

一些通用的解决方案方向:

  • 使用仲裁员。这可以像全局或每个节点(在 NUMA 的情况下)锁定整个资源分配过程一样简单,但也可以以无锁方式完成,例如优先考虑具有较低 ID 的工作人员。

  • 实现工作窃取:从另一个等待的 worker 回收部分分配的资源,但有一些内置的不公平性(例如,永远不要从 worker 0 获取)。这需要跟踪部分分配的资源和一些线程间(进程间)通信。

  • 尝试释放:尝试获取资源,如果失败,则释放部分获取的资源并放弃执行(等待一小段时间)。 Howard Hinnant 对此做了一些研究,可以在 here 中找到。

根据您的问题描述,我建议使用中控锁的简单解决方案,或者更好的是,首先尝试避免该问题。鉴于您正在开发虚拟内存分配器,因此有一些专门针对此的研究,例如这个来自jemalloc