VC多线程访问数据库的数据传递问题

在VC下出现的问题,现将问题描述如下:
程序中有两个线程:主线程,Mytheard;
在主线程(MFC基于单文档),的DOC类中,添加了成员:CMyDB m_MyDB;
CMyDB中包括public的数据成员指针:_ConnectionPtr m_pConnectDB;
那么现在我想在Mytheard线程中(入口参数为VIEW类的this),然后调用:p_View->p_Doc->m_MyDB.m_pConnectDB访问数据库,为什么会在程序退出报错呢?
我经调试发现:
1Mytheard从进入到退出都是对的,但Mytheard退出后,程序退出时却报错。
2绝对和数据库相关,因为如果不连接数据库就不会出报错。不管是否访问,只要连接,也即调用了_ConnectionPtr的函数就会出错。我在网上查看了一些内容,据说ConnectionPtr 是一个智能指针,不能像用一般指针那样用它。与COM原理相关。我想请教一下解决的方法是什么?
3.Mytheard的第一句为:coinitialize,结束前用:CoUninitialize。
主线程在APP中的initalistance中调用:AfxOleInit.这些应该正确吧。(改成coinitialize,CoUninitialize成对调用效果一样)

整体上我想做的事情就是在DOC中定义一个包含 ConnectionPtr 数据成员的对象。
然后在主线程和自定义的线程中都能通过该对象ConnectionPtr来访问数据库。

说一些概念性的东西吧。
COM操作,它有一套自己关于跨线程和跨进程的模型,这是个复合模型,会衍生出大约7,8种组合。学习COM,这个是一定要吃透的。楼主阅读一下关于CoInitializeEx函数的帮助文档,能多多少少体会到一些。但如果没学习过COM,光看MSDN的帮助文档,如坠云里雾里一般,很难理解的。因此,建议买本COM的书,稍微参阅一下,其次网上譬如CSDN中有很多热心人写的关于线程进程有关的COM模型,和使用规则,优缺点,可以拜读一下!

在MFC中,可能不太会形成跨线程传递变量的危害性,这种观念吧。所以,在MFC中,似乎我们能随心所欲在线程之间传递变量,但其实是不对的,典型的就是主线程创建的窗口和控件,最好不要在其它线程中直接操纵,而是通过线程间通信的方法,让创建窗口和控件的主线程来操纵窗口和控件。

因此,变量是不能乱传地,到了COM中,这个限制是非常明显的,COM中有概念叫MARSHAL、PROXY、STUB,当然它主要是进程相关的概念,同样说明了,非线程自己创建的东西,不是该线程使用就会有问题。

像VIEW这种界面的东西不要随便乱传给工作线程这种非界面线程。
我的建议是:
建工作线程,因为数据库操作及从数据库反馈到程序级的数据需要进行再加工,这些步骤都可能会非常耗时,耗时操作放在界面线程,会使界面线程无法处理WM_XXX的消息,造成界面假死。因此,像智能指针这种东西放到工作线程里进行独立管理,工作线程通过智能指针向数据库要数据,然后处理,存放数据结果到程序中约定的地方,如全局变量,虚拟内存等地方。数据处理完,通过自定义消息,向界面线程发送自定义消息,使界面线程能够在自定义消息中,将保存的数据显示到界面中,发送线程消息有个函数就是PostThreadMessage。
其他的细微细节也可以考虑,到底是创建自己的线程,还是使用线程池等。随着经验的丰富,会考虑很多问题的,关键是理论知识要学,实践也不能没有。

最后就是概念修正, _ConnectionPtr它是一个标准的C++类,C++类可以重载->操作符,这个被重载的指针操作符,使得通过该类实例化的变量在实际使用时,行为更像是一个指针,而不是个普通变量,这个被重载的指针操作符才是智能指针,而不是指_ConnectionPtr类是智能指针,顶多说它是个智能指针类,我也见过有翻译成灵巧指针的,英文原版是SMART POINTER。
温馨提示:答案为网友推荐,仅供参考
第1个回答  2010-09-07
我也不知道对不对..我自己的经验..

线程回调函数必须是静态函数..全局函数..就是说你内存里必须存在..

你在mytherad中调用DOC类中的数据..因为DOC类并没有建立对象.他就会找不到你所调用的地址..

解决办法..就是把你要调用的数据设为静态的或者是全局的..也就是说内存里要存在的..这样回调函数才能找到..
第2个回答  2010-09-07
可能是COM调用越界了(即在CoUninitialize()调用完成后,再调用COM的方法)因为全局变量的析构在最后才调用!检查你的 CoInitialize(NULL)和CoUninitialize()调用,你在调用CoUninitialize()的位置设断点,在 析构函数(任何语句处)也设断点.然后退出程序,看看程序先运行到哪个断点处就明白了~~~

建议:修改程序结构 ,不要在全局对象中使用智能指针~
试验用参数COINIT_MULTITHREADED 或COINIT_APARTMENTTHREADED 调用
CoInitializeEx来初始化COM看看。