线程安全地构造C ++对象(MFC CRecordset)

时间:2009-10-06 14:48:14

标签: c++ multithreading mfc thread-safety recordset

我们正在尝试构建一个提供MFC CRecordset(或者,实际上是CODBCRecordset类)线程安全性的类。实际上,对于打开和移动记录集等各种函数来说,一切看起来都非常好(我们将这些调用与关键部分联系起来),然而,仍然存在一个问题,这个问题似乎在实践中引入了死锁。

问题似乎在于我们的构造函数,如下所示:

CThreadSafeRecordset::CThreadSafeRecordset(void) : CODBCRecordset(g_db)
{ // <-- Deadlock!
}

另一个线程可能是最终在CThreadSafeRecordset :: Close()中的一个,尽管我们守护了封闭的Close调用,但这并不重要,因为构造函数没有意识到线程。我认为原来的CRecordset类是罪魁祸首,在建设时做坏事。我已经四处寻找编程技术来解决这个问题,但我不确定什么是最好的解决方案?由于我们没有代码并且无法控制构造函数中的其他代码,因此我们无法在临界区中包含任何特殊内容......?

更新:感谢您的输入;我已将我最终得到的内容标记为我的问题的答案。这与返回shared_ptr作为返回的实例相结合,以便于更新现有的线程无意识代码。

2 个答案:

答案 0 :(得分:2)

您可以将CThreadSafeRecordset构造函数设为私有,然后提供参与锁定并返回实例的公共工厂方法。

答案 1 :(得分:1)

如果没有办法让CODBCRecordset将其线程不安全的操作移出构造函数(默认构造函数后跟一个Initialize()调用,比如说),你总是可以使用合成而不是继承。让CThreadSafeRecordset成为CODBCRecordset的包装器而不是它的子类。这样,你可以随时明确地构建你的记录集,并且可以用适当的严格来保护它。

当然,缺点是你必须包装你希望公开的每个 CODBCRecordset方法,即使是那些与你的线程保证无关的方法。 cpp文件中的C宏(以便它无法逃脱并折磨你的客户端)可能会有所帮助。