多线程与引用计数:每个线程分别计算变量

时间:2013-01-31 09:19:31

标签: multithreading gtk pthreads glib reference-counting

我一直在玩glib,

  1. 利用引用计数来管理其对象的内存;
  2. 支持多线程。
  3. 我无法理解的是他们如何一起玩。 即:

    1. glib中,每个线程似乎都没有增加在其输入上传递的对象的引用计数,AFAIK(我将它们称为线程共享对象)。这是真的吗? (或者我刚刚找不到合适的代码片段?)除了主线程(负责引用它们)之外,通常的做法是不增加每个线程的线程共享对象的引用,它们共享它们吗? / LI>
    2. 但是,每个线程都会增加对象的引用计数,这些对象是由它自己动态创建的。程序员是否应该在每个线程中不提供相同的变量名称以防止名称冲突和内存泄漏? (例如,在我的图片中,thread2不应该创建一个名为output_object的堆变量,否则它将与thread1的同名堆变量冲突)?
    3. 更新:答案(问题2)为否,导致可见范围     那些变量不相交:     Is dynamically allocated memory (heap), local to a function or can all functions in a thread have access to it even without passing pointer as an argument

      我的问题的说明:

      enter image description here

2 个答案:

答案 0 :(得分:2)

我认为线程与理解参考计数器的使用无关。关键是所有权和生命周期,而线程只是受此影响的一件事。这有点难以解释,希望我能用例子来说明这一点。

现在,让我们看一下给定的例子,其中main()创建一个对象并使用该对象启动两个线程。问题是,谁拥有创建的对象?简单的答案是main()和两个线程共享此对象,因此这是共享所有权。为了对此进行建模,您应该在每次调用pthread_create()之前递增refcounter。如果调用失败,则必须再次递减,否则启动的线程负责在完成对象时执行此操作。然后,当main()终止时,它还应该释放所有权,即减少refcounter。 一般规则是在添加所有者时,增加refcounter。当一个所有者完成该对象时,它会递减refcounter,最后一个会用该对象销毁该对象。

现在,为什么代码不这样做?首先,您可以将第一个线程添加为所有者,然后将main()的所有权传递给第二个线程。这将保存一个递增/递减操作。这仍然不是正在发生的事情。相反,根本没有完成引用计数,原因很简单,它没有被使用。引用计数的目的是协调作为对等方的不同所有者之间动态分配的对象的生存期。虽然这里的对象是由main()创建并拥有的,但是这两个线程不是对等体,而是主体的奴隶。由于main()是控制线程开始/停止的主控器,因此它不必协调对象的生命周期。

最后,尽管这可能是由于您的代码的示例,我认为main只是泄漏了引用,依赖于操作系统来清理。虽然这不美观,但并没有伤害。通常,您可以分配一次对象,然后在某些情况下永久使用它们而不进行任何引用计数。这方面的一个示例是应用程序的主窗口,您只需要一次并且对于整个运行时。你不应该重复分配这样的对象,因为那时你会有一个显着的内存泄漏,随着时间的推移会增加。这两种情况都会被像valgrind这样的工具捕获。

关于你的第二个问题,关于你期望的堆变量名冲突,它不存在。函数本地的变量名称不会发生冲突。这不是因为它们被不同的线程使用,但即使同一个函数被同一个线程调用两次(想想递归!),每次调用函数的局部变量都是不同的。此外,变量名称适用于人类读者。编译器完全消除了这些。

答案 1 :(得分:1)

<强>更新

正如matthias所说,GObject不是线程安全的,只有引用计数函数。

原创内容:

GObject应该是thread safe,但我自己从未玩过这个......