【问题标题】:Locking in function hierarchies锁定函数层次结构
【发布时间】:2014-11-12 01:33:24
【问题描述】:

我目前遇到了一些关于 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,哪个应该假设它已经被锁定? (显然,如果一个函数假定持有某些锁,那么它只能调用 至少做出同样强假设但除此之外的函数?)

我的问题如下:实践中使用了这些方法中的哪一种,为什么?

提前致谢

hfhc2

【问题讨论】:

    标签: c++ multithreading locking mutex


    【解决方案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 要求的并且需要记录在案。

    【讨论】:

      【解决方案2】:

      1.传递是否锁定的指示符:

      您将锁定选择权交给调用者。这很容易出错:

      • 调用者可能没有做出正确的选择
      • 调用者需要知道你的对象的实现细节,从而破坏了封装的原则
      • 调用者需要访问互斥锁
      • 如果您有多个对象,最终会为死锁提供条件

      2。递归锁:

      您已经强调了这个问题。

      3.将锁定责任传递给调用者:

      在您提出的不同备选方案中,这似乎是最一致的。与 1 相反,您不提供选择,但您完全负责锁定。这是使用 func_2 的合同的一部分。

      您甚至可以断言是否在对象上设置了锁,以防止错误(尽管检查会受到限制,因为您不一定能够验证谁拥有锁)。

      4.重新考虑您的设计:

      如果您需要在 func_2 中确保对象被锁定,则意味着您在其中有一个必须保护的临界区。有可能这两个函数都需要锁定,因为它们对 obj 执行一些较低级别的操作,并且需要防止对象不稳定状态的数据竞争。

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

      【讨论】:

      • 作为补充:我有时会在观察者模式中使用回调,例如每当数据发生变化时。在回调期间,我希望对象处于需要持有锁的一致状态...
      • 自己的好问题!观察者将在修改线程中被调用。因此,您需要管理观察者的并发性(单独的数据结构,不同的锁),这是导致并发瓶颈的最佳候选者,或者更糟糕的是,如果您在调用观察者时持有锁,则会出现死锁。建议:有一个异步管理的观察者(减少瓶颈情况)?或者制作所需值的一致副本,释放锁并将值传递给观察者?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-05
      • 2021-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多