[问题] 请问物件在multithread下的生成与控管

楼主: Keitaro (动き出す时间...)   2014-08-22 03:53:18
开发平台(Platform): (Ex: VC++, GCC, Linux, ...)
VC2008 MFC
问题(Question):
请教物件在multi-thread的情况下,物件的生成、控管、以及删除的时机
补充说明(Supplement):
不好意思,不才小弟又上来请教一下各位了。
我想跟版上的各位高手请教一下,在multi-thread下,
物件生成、控管、以及删除的时机与原则。
小弟工作上接手的project是MFC。
以往我的观念是,一个母物件底下有什么子物件,就在母物件底下生成(new)。
要删除子物件,就在母物件的解构里面执行(delete)。
子物件里面如果还有包新的物件,照以上原则处理。
但我接手的这个proj,以前同事开发的写法不是这样。
当MainFrame建立起来后,就一次把所有的dialog全部建立起来。
比方说这样的架构
MainFrame - Sub-DialogA - Sub-DialogA1
\ Sub-DialogA2
\
Sub-DialogB - Sub-DialogB1
在MainFrame的OnCreate把5个dialog全部new起来,
然后分别把Dialog A1/A2的指标传给DialogA的指标,
DialogB1的指标传给DialogB的指标。
删除,当然全部在MainFrame的解构里面做。
当然这样也不是不可以,好处是把所有物件统一生成,统一删除在同一处。
只是我不太喜欢,从属关系要追一下程式码。
追code不方便,除了统一生成统一删除以外我不知还有什么好处。
最近开始学习使用Multithread,碰上了一个问题。
我要写一个自动下载的功能,架构如下
Create Create Create
MainFrame -> DialogA -> _MonitorThread -> _DownloadThread
(push queue) (pop queue)
1. MainFrame开启timer自动push queue
2. DialogA在MainFrame底下生成
3. DialogA生成后开启_MonitorThread
4. _MonitorThread监控queue,如果没有东西下载(_DownloadThread指标为null),queue
里面有东西,pop第一个执行_DownloadThread
5. 下载进度,_DownloadThread会显示在DialogA中
5. 当_DownloadThread执行尚未结束前,_MonitorThread持续等待(WaitForSingleObject)
出现的问题是,如果user直接把UI整个关掉,MainFrame跑了OnDestroy,
在解构开始执行之前,我要等这两个thread先结束,在abort flag丢给thread后,
我在MainFrame::OnDestroy里面写WaitForSingleObject(_MonitorThread)
测试结果发现常常会关不掉,检查后发现我这样的写法会有dead lock。
问题出在于,_DownloadThread正好要把DialogA的显示文字作更新的动作,
DialogA在MainFrame底下生成,可是此时MainFrame执行WaitForSingleObject,
所以无法回应,形成死结。
找到原因后,我想我的DialogA不能在MainFrame里面建立,要在thread里面建立才行。
create create create create
MainFrame -> _TestThread -> DialogA -> _MonitorThread -> _DownloadThread
在MainFrame里面直接建一个新的_TestThread,只做一件事,把DialogA给建立起来。
//create thread
//CWinThread* pTestThread; 写在MainFrame的header里面
pTestThrtead = AfxBeginThread(CreateDlgFun, this);
//_TestThread
UINT CMainThread::CreateDlgFun(LPVOID pParam)
{
CMainFrame* pMF = (CMainFrame*)pParam;
CDialogA* pA = new CDialogA();
...
...
}
//MainFrame OnDestroy
void CMainFrame::OnDestroy()
{
...... // WaitForSingleObject(_TestThread)
}
我对于DialogA的建立,产生疑问:
1. CDialogA* pA = new CDialogA();
如果pA为local变量,那我就必须要让Thread的完成下载动作、或user取消之前,
不能结束,否则pA就消失了。
2. 如果pA被宣告在MainFrame的header里面
// in CMainFrame header
class CMainFrame
{
CDialog* pA;
...
}
//_TestThread
UINT CMainThread::CreateDlgFun(LPVOID pParam)
{
CMainFrame* pMF = (CMainFrame*)pParam;
if (pA != NULL)
pA = new CDialogA();
...
...
}
改成这样的写法,pA储存在物件中,生命周期跟物件相同,我要对pA做操作会比较容易。
但这样一来,会不会产生原来的问题?
虽然DialogA在Thread里面new出来,但是pA还是放在MainFrame物件中。
这样当_DownloadThread要求DialogA变更显示文字时,会不会dead lock?
我的想法是,Dialog是thread建的,应该是thread掌管,会不会回应是thread控制,
pA只是内存的储存位置,应该没关系吧?
如果是的话,那么pA new的时候需不需要Lock起来?
再来,删除的时机为何?
1. 如果pA是local变量,那么只要在thread结束前执行delete就好,没问题。
2. 如果pA储存在MainFrame物件呢?
我想应该还是要在thread结束前删除吧?如果留给MainFrame去删除,
proj越来越大、thread越多,应该会产生一堆问题。
请教版上各位高手,在multithread的物件管理的原则?
观念可能很基本,但我这菜鸟觉得如果写multithread观念没建好,管理出问题,
恐怕会有解不完的bug。
另外还有个问题顺便问一下。
我知道thread function要被宣告成static。
class里面的任何东西一旦被宣告成static,
class宣告的所有物件会共用被宣告为static的元件。
但我不解的是,那么,thread的static function,
如果不放在物件里面,变成global function,有什么差别呢?
1. UINT static CMainFrame::_TestThread()
2. UINT static _TestThread()
请问有什么差别?
还请版上各位高手指教,感激不尽!
作者: Killercat (杀人猫™)   2014-08-22 12:45:00
这优点就是pop dialog很快 因为早就生好了缺点就是会略为拖到启动时间 不过这个我认为不严重
作者: TeaEEE (爱不趴 不爱趴)   2014-08-22 19:26:00
要避免在thread中生成UI物件,因为MS不保証物件生成是threThreadsafe
作者: EdisonX (卡卡兽)   2014-08-24 00:53:00
在很多 setting dialog 很多的时候 , 这方法不就... orz
作者: tyc5116 (累人啊....)   2014-08-26 09:22:00
同意3F,一个大原则,Thread只用来做数值运算,逻辑上的处理UI的部份都避免掉你的"5. 下载进度",我会把更新的数值放某变量内然后Dialog开个Timer,作为更新接口上的资讯如此,Thread可以完全避免掉UI的部份

Links booklink

Contact Us: admin [ a t ] ucptt.com