锁定功能层次结构

时间:2014-09-17 21:05:36

标签: c++ multithreading locking mutex

我目前遇到一些关于C ++并发编程的设计问题 我想知道你是否可以帮助我:

假设某些函数func对某个对象obj起作用。在这些操作期间,有必要持有一个锁(可能是obj的成员变量)。现在假设 func在持有锁时调用子功能func_2。现在func_2对已经锁定的对象进行操作。但是,如果我还想在没有按住锁的情况下从其他地方拨打func_2该怎么办?应该func_2锁定obj还是不应该?我看到3个可能性:

  1. 我可以将bool传递给func_2,表明是否需要锁定。 这似乎引入了很多样板代码。
  2. 我可以使用递归锁定,并始终在obj中锁定func_2。递归锁 好像 但是有问题,请参阅here
  3. 我可以假设func_2的每个来电者都已拥有锁。我会 记录这个并且可能强制执行此操作(至少在调试模式下)。是 让函数做出关于哪些锁是否锁定的假设是合理的 由调用线程持有?更一般地说,我如何从设计角度做出决定 一个函数是否应该锁定Obj哪个应该假定它已被锁定? (显然,如果函数假定某些锁被保持,那么它只能调用 至少具有同样强烈假设但除此之外的函数?)
  4. 我的问题如下:在实践中使用了哪一种方法?为什么?

    提前致谢

    hfhc2

2 个答案:

答案 0 :(得分:1)

<强> 1。传递指示符是否锁定:

您为锁定者提供锁定选择。这很容易出错:

  • 来电者可能没有做出正确的选择
  • 调用者需要知道有关对象的实现细节,从而违反封装原则
  • 来电者需要访问互斥锁
  • 如果您有多个对象,最终会促成死锁条件

<强> 2。递归锁定:

您已经突出显示了该问题。

第3。将锁定责任传递给来电者:

在您提出的不同替代方案中,这似乎是最一致的。与1相反,你不做出选择,但你完全承担了锁定的责任。这是使用func_2的合同的一部分。

你甚至可以断言是否在对象上设置了一个锁,以防止出现错误(尽管由于你不一定能够确定拥有锁的人是否有限,因此检查会受到限制)。

4.重新考虑您的设计:

如果您需要在func_2中确保对象已被锁定,则表示您必须保护其中的关键部分。两个函数都有可能需要锁定,因为它们对obj执行一些较低级别的操作,并且需要防止对象的不稳定状态下的数据争用。

我强烈建议看看是否可以从func和func_2中提取这些较低级别的例程,并将它们封装在obj上的更简单的原始函数中。这种方法也可以有助于锁定更短的序列,从而增加实际并发的机会。

答案 1 :(得分:1)

好的,就像另一个后续行动一样。我最近阅读了the API documentation of glib,特别是有关消息传递队列的部分。我发现在这些队列上运行的大多数函数有两种变体,名为functionfunction_unlocked。这个想法是,如果程序员想要执行单个操作,比如从队列中弹出,可以使用g_async_queue_pop()来完成。该功能自动处理队列的锁定/解锁。但是,如果程序员想要不间断地弹出两个元素,可以使用以下序列:

GAsyncQueue *queue = g_async_queue_new();

// ...

g_async_queue_lock(queue);

g_async_queue_pop_unlocked(queue);
g_async_queue_pop_unlocked(queue);

g_async_queue_unlock(queue);

这类似于我的第三种方法。同样也存在关于某些锁定状态的假设,它们是API所要求的并且需要记录。

相关问题