C ++,如何为多个线程制作高效的1个共享资源数组
C++, how to make efficient, 1 shared array of resources for multiple threads
描述:
我有多个线程 (4-32)。这些线程都可以访问一个数组:int resources[1024]。
Resources 数组包含不同的值 (0-1023)。单个资源(int)只能有一个实例。每个线程需要不同数量的资源,这些资源在某些时候 return 返回数组。线程可以多次请求资源并且 return 一次只能请求一部分资源。每个线程都通过 2 种方法访问此数组:GetElement()、ReturnElement(int element)
GetElement():此方法锁定部分,从资源数组中删除最后一个元素并将其return发送到调用线程。每个线程都在循环调用 n 个资源的方法。
ReturnElement(int element):此方法锁定部分,将参数中的资源元素追加到数组中的最后一个元素之后。每个线程都在循环调用 n 个资源的方法。
当前的实现方式存在缺陷,当多个线程同时获取资源时,none 个线程可能会获得所需的数量。我正在考虑在单个线程获取或 returns 资源时锁定对数组的访问,然后将其解锁。这种方法阻塞了所有其他线程,这可能是一个问题。
有没有更有效的方法?
此问题是 dining philosophers problem 的变体,这是一个活跃的研究领域。有一些解决方案,但 none 是完美的,通常在这种情况下,以通用和恒定时间的方式避免死锁是有问题的。
一些通用的解决方案方向:
使用仲裁员。这可以像全局或每个节点(在 NUMA 的情况下)锁定整个资源分配过程一样简单,但也可以以无锁方式完成,例如优先考虑 ID 较低的工作人员。
实施工作窃取:从另一个等待的工作人员那里回收部分分配的资源,但有一些内置的不公平(例如,永远不要从工作人员 0 那里拿走)。这需要跟踪部分分配的资源和一些线程间(进程间)通信。
Try-and-release:尝试获取资源,如果失败,释放部分获取的资源并yield执行(等待一小段时间)。 Howard Hinnant 对此做了一些研究 here。
鉴于您的问题描述,我会推荐一个带有中央锁定的简单解决方案,或者更好的是,首先尝试避免该问题。鉴于您正在开发虚拟内存分配器,因此有一些专门针对此的研究,例如这个来自 jemalloc.
描述:
我有多个线程 (4-32)。这些线程都可以访问一个数组:int resources[1024]。 Resources 数组包含不同的值 (0-1023)。单个资源(int)只能有一个实例。每个线程需要不同数量的资源,这些资源在某些时候 return 返回数组。线程可以多次请求资源并且 return 一次只能请求一部分资源。每个线程都通过 2 种方法访问此数组:GetElement()、ReturnElement(int element)
GetElement():此方法锁定部分,从资源数组中删除最后一个元素并将其return发送到调用线程。每个线程都在循环调用 n 个资源的方法。
ReturnElement(int element):此方法锁定部分,将参数中的资源元素追加到数组中的最后一个元素之后。每个线程都在循环调用 n 个资源的方法。
当前的实现方式存在缺陷,当多个线程同时获取资源时,none 个线程可能会获得所需的数量。我正在考虑在单个线程获取或 returns 资源时锁定对数组的访问,然后将其解锁。这种方法阻塞了所有其他线程,这可能是一个问题。
有没有更有效的方法?
此问题是 dining philosophers problem 的变体,这是一个活跃的研究领域。有一些解决方案,但 none 是完美的,通常在这种情况下,以通用和恒定时间的方式避免死锁是有问题的。
一些通用的解决方案方向:
使用仲裁员。这可以像全局或每个节点(在 NUMA 的情况下)锁定整个资源分配过程一样简单,但也可以以无锁方式完成,例如优先考虑 ID 较低的工作人员。
实施工作窃取:从另一个等待的工作人员那里回收部分分配的资源,但有一些内置的不公平(例如,永远不要从工作人员 0 那里拿走)。这需要跟踪部分分配的资源和一些线程间(进程间)通信。
Try-and-release:尝试获取资源,如果失败,释放部分获取的资源并yield执行(等待一小段时间)。 Howard Hinnant 对此做了一些研究 here。
鉴于您的问题描述,我会推荐一个带有中央锁定的简单解决方案,或者更好的是,首先尝试避免该问题。鉴于您正在开发虚拟内存分配器,因此有一些专门针对此的研究,例如这个来自 jemalloc.