线程安全地构造 C++ 对象(MFC CRecordset)
Posted
技术标签:
【中文标题】线程安全地构造 C++ 对象(MFC CRecordset)【英文标题】:Constructing a C++ object (the MFC CRecordset) thread-safely 【发布时间】:2009-10-06 14:48:13 【问题描述】:我们正在尝试构建一个提供 MFC CRecordset(或者,实际上是 CODBCRecordset 类)线程安全的类。对于各种功能,例如打开和移动记录集(我们将这些调用与关键部分括起来),实际上一切似乎都很好,但是,仍然存在一个问题,这个问题似乎在实践中引入了死锁。
问题似乎出在我们的构造函数上,像这样:
CThreadSafeRecordset::CThreadSafeRecordset(void) : CODBCRecordset(g_db)
// <-- Deadlock!
尽管我们保护了封闭的 Close 调用,但另一个线程可能最终在 CThreadSafeRecordset::Close() 中结束,但这并不重要,因为构造函数不知道线程。我认为最初的 CRecordset 类是罪魁祸首,在施工时做坏事。我一直在寻找解决这个问题的编程技术,但我不确定什么是最好的解决方案?由于我们没有代码,也无法控制构造函数中的其他代码,所以我们不能在临界区中包装任何特殊的东西......?
更新:感谢您的意见;我已经将我最终得到的内容标记为我的问题的答案。这与返回 shared_ptr 作为返回实例相结合,以便于更新现有的线程不感知代码。
【问题讨论】:
【参考方案1】:您可以将CThreadSafeRecordset
构造函数设为私有,然后提供一个参与锁定并返回实例的公共工厂方法。
【讨论】:
【参考方案2】:如果无法使 CODBCRecordset 将其线程不安全操作移出构造函数(例如,默认构造函数后跟 Initialize() 调用),则始终可以使用组合而不是继承。让 CThreadSafeRecordset 成为 CODBCRecordset 的包装器,而不是它的子类。这样一来,您就可以随时明确地构建您的记录集,并且可以以任何适当的严谨性来保护它。
当然,缺点是您必须包装每个您希望公开的 CODBCRecordset 方法,即使是那些与您的线程保证无关的方法。 cpp 文件中的 C 宏(这样它就不会逃脱并影响您的客户端)可能会有所帮助。
【讨论】:
以上是关于线程安全地构造 C++ 对象(MFC CRecordset)的主要内容,如果未能解决你的问题,请参考以下文章
在 Visual C++ 6.0 MFC 中,CString 是不是可以像简单类型而不是类一样被安全地对待?