我认为线程与理解引用计数器的使用无关。重点是所有权和生命周期,线程只是受此影响的一件事。这有点难以解释,希望我会通过示例更清楚地说明这一点。
现在,让我们看一下 main() 创建一个对象并使用该对象启动两个线程的给定示例。问题是,谁拥有创建的对象?简单的答案是 main() 和两个线程共享这个对象,所以这是共享所有权。为了对此建模,您应该在每次调用 pthread_create() 之前递增 refcounter。如果调用失败,您必须再次递减它,否则启动线程有责任在对象完成时执行此操作。然后,当 main() 终止时,它也应该释放所有权,即递减 refcounter。一般规则是,当添加所有者时,增加 refcounter。当所有者使用完该对象时,它会递减 refcounter,最后一个会销毁该对象。
现在,为什么代码不这样做?首先,您可以将第一个线程添加为所有者,然后将 main() 的所有权传递给第二个线程。这将节省一次递增/递减操作。但这仍然不是正在发生的事情。相反,根本没有进行引用计数,简单的原因是它没有被使用。引用计数的目的是在作为对等的不同所有者之间协调动态分配对象的生命周期。不过,这里的对象是由 main() 创建和拥有的,这两个线程不是对等线程,而是 main 的从属线程。由于 main() 是控制线程启动/停止的主控器,因此它不必与它们协调对象的生命周期。
最后,虽然这可能是由于您的代码的示例性,但我认为 main 只是泄漏了引用,依赖于操作系统进行清理。虽然这并不漂亮,但它并不伤人。通常,您可以分配对象一次,然后在某些情况下永远使用它们而无需任何引用计数。这方面的一个例子是应用程序的主窗口,您只需要一次并且在整个运行时都需要它。但是,您不应该重复分配此类对象,因为这样您就会有明显的内存泄漏,并且会随着时间的推移而增加。不过,这两种情况都会被 valgrind 等工具捕获。
关于您的第二个问题,关于您期望的堆变量名称冲突,它不存在。函数局部变量名不能冲突。这不是因为它们被不同的线程使用,而是即使同一个函数被同一个线程调用两次(想想递归!)每次调用函数中的局部变量都是不同的。此外,变量名称是供人类阅读的。编译器完全消除了这些。