algorithm - 如何有效地调试共享内存中的引用计数问题?

标签 algorithm multithreading debugging shared-memory reference-counting

假设您在共享内存中有一个引用计数对象。引用计数表示使用对象的进程数,进程负责通过原子指令递增和递减计数,因此引用计数本身也在共享内存中(它可以是对象的一个​​字段,或者对象可能包含指向计数的指针,如果他们有助于解决这个问题,我愿意接受建议)。有时,一个进程会有一个错误,阻止它减少计数。如何尽可能轻松地找出哪个进程没有递减计数?

我想到的一个解决方案是给每个进程一个 UID(也许是它们的 PID)。然后当进程递减时,它们将它们的 UID 推送到与引用计数一起存储的链表(我选择链表是因为您可以使用 CAS 原子地追加到头部)。当你想要调试时,你有一个特殊的进程来查看共享内存中仍然存在的对象的链接列表,并且任何应用程序的 UID 不在列表中的都是尚未减少计数的应用程序。

此解决方案的缺点是它的内存使用量为 O(N),其中 N 是进程数。如果使用共享内存区域的进程数量很大,并且您有大量对象,那么这很快就会变得非常昂贵。我怀疑可能有一个半途而废的解决方案,其中使用部分固定大小的信息,您可以通过某种方式缩小可能进程列表的范围来协助调试,即使您无法查明单个进程也是如此。或者,如果您可以在只有一个进程没有减少时检测到哪个进程没有减少(即无法处理检测到 2 个或更多进程未能减少计数),这可能仍然会有很大帮助。

(这个问题有更多的“人性化”解决方案,比如确保所有应用程序都使用相同的库来访问共享内存区域,但是如果共享区域被视为二进制接口(interface)并且并非所有进程都将被由您编写的不受您控制的应用程序。此外,即使所有应用程序都使用相同的库,一个应用程序也可能在库外有一个错误,以这种方式破坏内存,从而阻止减少计数。是的,我正在使用不安全的语言,如 C/C++ ;)

编辑:在单进程情况下,您将拥有控制权,因此您可以使用 RAII (在 C++ 中)。

最佳答案

您可以为每个对象仅使用一个额外的整数来做到这一点。

将整数初始化为零。当进程增加对象的引用计数时,它会将其 PID 异或为整数:

object.tracker ^= self.pid;

当进程递减引用计数时,它会做同样的事情。

如果引用计数始终为 1,则跟踪器整数将等于增加它但没有减少它的进程的 PID。


这是有效的,因为异或是可交换的( (A ^ B) ^ C == A ^ (B ^ C) ),所以如果一个进程对跟踪器进行异或它自己的 PID 偶数次,这与将它与 PID ^ PID 进行异或运算相同 - 为零,这使跟踪器值不受影响。

您也可以使用无符号值(定义为换行而不是溢出)- 在使用计数递增时加上 PID,在递减时减去它。

关于algorithm - 如何有效地调试共享内存中的引用计数问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2220108/

相关文章:

java - 对于可变长度数据应考虑哪些哈希算法

java - 使用 Samurai 进行线程转储分析

java - 在一个线程中创建数据库实体并尝试在另一个线程中检索相同的实体给出不同的结果

Java newSingleThreadExecutor 垃圾回收

php - 引用 - 这个错误在 PHP 中意味着什么?

C++ 代码输出负值

debugging - 不推荐使用 CreateProcessW 吗?

c++ - 同一个数组上的堆栈和队列操作

在 O(n log n) 时间内找到特殊点 k 的算法

python - 在 Python 中使用多个条件过滤数据的最佳算法