编码风格:在内部还是外部锁定/解锁?

4

另一个可能有点愚蠢的样式问题:

并发应该如何锁定?执行程序或调用者应该负责锁定线程吗?

例如,在任何特定语言中...

Caller::callAnotherThread() {
    _executor.method();
}

Executor::method() {
    _lock();
    doSomething();
    _unlock();
}

或者

Caller::callAnotherThread() {
    _executor.lock()
    _executor.method();
    _executor.unlock()
}

Executor::method() {
    doSomething();
}

我对线程和锁定的知识很少,因此我希望确保代码的稳健性。第二种方法允许不安全的线程调用... 实际上您可以在不执行任何类型的锁定的情况下调用_executor.method()。

能帮忙吗?

谢谢,


锁定/解锁(临界区处理)非常依赖于编程语言。有些语言已经内置了对临界区的支持,而有些则没有。你有特定的语言想法吗?(pthreads 建议使用 C/C++) - Kosi2801
3个回答

5
被调用者而不是调用者应该进行锁定。被调用者是唯一知道需要同步的内容,并能够确保它被同步的人。如果你让调用者来进行锁定,那么会带来以下三个问题:
  1. 增加用户使用函数/类的负担,增加设计黏度。
  2. 允许调用者在没有锁定的情况下更新共享状态。
  3. 引入死锁的可能性,如果不同的函数以不同的顺序获取多个锁。

+1. 说得好,但我认为有些情况下锁定外部也是合理的。 - Skurmedel
很好,这就是我目前的进展。 :D - Stephen Furlani
我对这个教条持有不同意见。在 Boost.Thread 文档中,关于内部锁定和外部锁定的讨论非常好:链接 我认为它很好地阐述了外部锁定的优势。特别是看看开始的那一节:“内部锁定对于许多实际的同步任务来说是不足够的…” - jwd
我从未遇到过需要使用外部锁定的情况,但我承认这样的情况可能存在。如果确实需要,那么显然你必须这样做。尽管如此,我仍然坚持我的建议。外部锁定是危险的(出于上述原因),应该避免使用。除非你别无选择,否则不要这样做。 - Peter Ruderman
我从未遇到过需要使用外部锁定的情况,但我承认这样的情况可能存在。如果确实需要,那么显然你必须这样做。尽管如此,我仍然坚持我的建议。外部锁定是危险的(出于上述原因),应该避免使用。除非你别无选择,否则不要这样做。 - Peter Ruderman

1

如果你在代码中使用锁,必须在手册文档上注明。否则你的代码会成为并行执行的瓶颈,用户将难以了解真相。


1
我们正在学习外部锁定的优势,如果您需要同时执行几个相互关联的粒度操作,或者使用内部结构的引用-您可以保持锁定,只要需要确保工作集免受其他线程的影响。
例如:管理项目列表的容器可能希望提供一个API来获取一个可变引用以访问一个项目。没有外部锁定,一旦函数调用完成,另一个线程就有可能锁定和修改数据。一个可行的解决方案是返回一个项目的副本,但这是低效的。
话虽如此,在某些情况下,如果您可以确信不需要比一个函数调用更长时间地保留锁,则内部锁定可能具有更清洁的API。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接