我对设计并发C ++应用程序的软件设计方面有一些疑问。我有一些高级问题(我知道基本知识,如'什么是锁/互斥/条件变量'等)。
锁定功能层次结构
假设某些函数func
对某个对象obj
起作用。在这些操作期间,有必要持有一个锁(可能是obj
的成员变量)。现在假设
func
在持有锁时调用子功能func_2
。现在func_2
对已经锁定的对象进行操作。但是,如果我还想在没有按住锁的情况下从其他地方拨打func_2
该怎么办?应该func_2
锁定obj
还是不应该?我看到3个可能性:
bool
传递给func_2
,表明是否需要锁定。
这似乎引入了很多样板代码。obj
中锁定func_2
。递归锁
好像
但是有问题,请参阅here。func_2
的每个来电者都已拥有锁。我会
记录这个并且可能强制执行此操作(至少在调试模式下)。是
让函数做出关于哪些锁是否锁定的假设是合理的
由调用线程持有?更一般地说,我如何从设计角度做出决定
哪个函数应该锁定Obj
哪个函数应该假定它已被锁定?你对此有什么建议吗?
公开锁定/互斥
到目前为止,我正在使用一种返回Mutex&
的方法,我将其提供给RAII Lock
。我认为,如果我使用C ++ 11,那么直接返回Lock
并重载移动构造函数将更加白痴。但这在C ++ 03中是不可能的。不过,是否存在不同的策略?
通常建议暴露互斥体还是应该避免使用?
对象层次结构
假设我有一个由多个页面组成的文档。可以通过以下方式访问此文档:
显而易见的方法是对文档进行大锁定,每个线程在访问文档时都必须保留。这具有明显的缺点,即渲染线程基本上连续工作,即使它们访问不同的页面。我有两个解决方案:
这些方法如何比较代码复杂性/执行时间?你会推荐什么?
跨线程锁定
再次考虑最后一点的情景。假设对任务和线程有一些亲和力。更重要的是,某些函数只需要从特定的线程调用(如果你必须知道我使用的是gtk,并且需要与gtk的任何交互必须从单个线程执行。)。方法似乎是添加一个由正确的线程处理的回调。但是,如果我在整个操作期间需要锁定,会发生什么?我是否应该通过线程传递(保持)锁定(这对我来说似乎是一种反模式)?
单线程支持
为了查找错误,我希望有一个单线程模式。假设我有一个调度程序
使用Runnable
方法传递run
类实例。通常,Scheduler充当Threadpool。它会通知一些空闲线程并将其传递给要处理的实例。我有一个天真的想法,让调度程序只调用run
方法本身。但这不起作用,因为调用函数可能会保存Runnable
需要锁定的锁,从而导致死锁。有一些简单的方法可以避免这种情况吗?我很想把一个bool
传递给锁,指示锁只是一个假人,应该什么都不做。但这可能只是将多线程问题(违反不变量)引入单线程环境......是否有一些简单的方法可以让Scheduler切换到单线程模式?
这些都是一些问题,我花了一段时间写下来:) 我非常感谢你的帮助。对文献的建议会 也欢迎。