Continuos data acquisition
Keith Vasilakes -- kvasilak@cyberoptics.com Thursday, December 19, 1996 Environment: VC++ 4.1, Win 95 I have an MFC app that needs to get data as fast as possible during the life of the app. The app contains three OCX's one of which is a graph on a DialogBar. I would like to call a function from within OnInitialUpdate() that just loops as fast as possible untill the program ends. However as we all know the user would be locked out of the app, the UI would never update and the user could not close the App. The first, and easiest, solution was to use a OnTimer event to allow some idletime processing to be done. This almost works, if the timer interval is too short toolbars etc dont get updated, if the timer interval is too long the app runs too slow. This most problematic when different machine speeds are involved. The second solution was to add an OnIdle Loop to the timer, like this, LONG lIdle = 0; while (AfxGetApp()->OnIdle(lIdle++)); This allows the view to be updated but if a toolbar is moved I get this OS error, "This application has performed an illegal operation and will be shutdown" The debugger shows that this is totally within MFC code not mine, Does anyone have a clue as to why calling OnIdle() from within a OnTimer() would be bad? I got the OnIdle() idea from "Programming Windows95 with MFC" by Prosie so I am surprised it doesn't work. Solution three; So now I bite the bullet and create a worker thread to handle the looping, this too almost works, Theproblem is that the thread cannot get a handle to the Graph OCX that is on a DialogBar, The thread can however get the handle if the Graph OCX is placed on the FormView ( not an option ) and I can get the Graph OCX's handle if I am within the main thread, like OnTimer(). the code to do this within the worker thread is; UINT MyThread(LPVOID pParam ) { BOOL *Run = (BOOL *)pParam; VARIANT vtRed, vtGreen, vtBlue; CMultiApp *pMyApp = ((CMultiApp *)AfxGetApp()); CCSGraph *MyGraph = pMyApp->m_MyDialogBar->GetChart(); while(*Run) { pMyApp->m_ctlXPG.QuickGrab(nCamera, nTimeout, nInit); pMyApp->m_ctlXPG.FetchFilterFrame(nNumLines, &vtRed, &vtGreen, &vtBlue); pMyApp->m_Graph->SetPlotReadings( vtRed); pMyApp->m_Graph->Refresh(); } m_MyDialogBar is a pointer to the DialogBar and is valid at the time of the function call. CCSGraph *CBarGraph::GetChart() { CCSGraph *pGraph = (CCSGraph *)GetDlgItem(IDC_CSGRAPHCTRL); return pGraph; } GetDlgItem() Fails if GetChart() is called from the worker thread but succeeds if called from the main thread. The thread idea would be the preferred way to run this App, if it worked. Any Ideas on how to get a pointer to that darn OCX? Is there any other way to run this app without either a timer or a worker thread? If someone can solve this I will nominate them the God of MFC :-) Thanks, Keith Vasilakes Manufacturing Software Engineer, CyberOptics
Kevin Tarn -- kevin@pln.com.tw Monday, December 23, 1996 You can create a structure that contains any data items you wanted passing to the worker thread. CCardStruct* pCard = new CCardStruct; pCard->m_bLaunchCardRecord = FALSE; pCard->m_szBeginLunch = dlg.m_szTimeFrom; pCard->m_szEndLunch = dlg.m_szTimeTo; AfxBeginThread((AFX_THREADPROC)BatchCollectionThread, LPVOID)pCard); Kevin Tarn kevin@pln.com.tw ---------- ±HҐуЄМ: kvasilak@cyberoptics.com[SMTP:kvasilak@cyberoptics.com] ¶З°e¤йґБ: 1996¦~12¤л19¤й PM 23:16 ¦¬ҐуЄМ: MFC-L@netcom.com ҐD¦®: Continuos data acquisition Environment: VC++ 4.1, Win 95 I have an MFC app that needs to get data as fast as possible during the life of the app. The app contains three OCX's one of which is a graph on a DialogBar. I would like to call a function from within OnInitialUpdate() that just loops as fast as possible untill the program ends. However as we all know the user would be locked out of the app, the UI would never update and the user could not close the App. The first, and easiest, solution was to use a OnTimer event to allow some idletime processing to be done. This almost works, if the timer interval is too short toolbars etc dont get updated, if the timer interval is too long the app runs too slow. This most problematic when different machine speeds are involved. The second solution was to add an OnIdle Loop to the timer, like this, LONG lIdle = 0; while (AfxGetApp()->OnIdle(lIdle++)); This allows the view to be updated but if a toolbar is moved I get this OS error, "This application has performed an illegal operation and will be shutdown" The debugger shows that this is totally within MFC code not mine, Does anyone have a clue as to why calling OnIdle() from within a OnTimer() would be bad? I got the OnIdle() idea from "Programming Windows95 with MFC" by Prosie so I am surprised it doesn't work. Solution three; So now I bite the bullet and create a worker thread to handle the looping, this too almost works, Theproblem is that the thread cannot get a handle to the Graph OCX that is on a DialogBar, The thread can however get the handle if the Graph OCX is placed on the FormView ( not an option ) and I can get the Graph OCX's handle if I am within the main thread, like OnTimer(). the code to do this within the worker thread is; UINT MyThread(LPVOID pParam ) { BOOL *Run = (BOOL *)pParam; VARIANT vtRed, vtGreen, vtBlue; CMultiApp *pMyApp = ((CMultiApp *)AfxGetApp()); CCSGraph *MyGraph = pMyApp->m_MyDialogBar->GetChart(); while(*Run) { pMyApp->m_ctlXPG.QuickGrab(nCamera, nTimeout, nInit); pMyApp->m_ctlXPG.FetchFilterFrame(nNumLines, &vtRed, &vtGreen, &vtBlue); pMyApp->m_Graph->SetPlotReadings( vtRed); pMyApp->m_Graph->Refresh(); } m_MyDialogBar is a pointer to the DialogBar and is valid at the time of the function call. CCSGraph *CBarGraph::GetChart() { CCSGraph *pGraph = (CCSGraph *)GetDlgItem(IDC_CSGRAPHCTRL); return pGraph; } GetDlgItem() Fails if GetChart() is called from the worker thread but succeeds if called from the main thread. The thread idea would be the preferred way to run this App, if it worked. Any Ideas on how to get a pointer to that darn OCX? Is there any other way to run this app without either a timer or a worker thread? If someone can solve this I will nominate them the God of MFC :-) Thanks, Keith Vasilakes Manufacturing Software Engineer, CyberOptics
mzsong@aztech.com.sg Monday, March 24, 1997 Hi, dear kevin and all mfc-member: Now it's the last problem I can ask. It's about use mfc object in a close-able thread. Kevin show the way to use mfc object in thread: class CMyDocument:public CDocumnet { public: CString str_Thread_Tmp; void OnTest(); } void CMyDocument::OnTest() { > CCardStruct* pCard =3D new CCardStruct; > pCard->m_bLaunchCardRecord =3D FALSE; > pCard->m_szBeginLunch =3D str_Thread_Tmp; > pCard->m_szEndLunch =3D dlg.m_szTimeTo; > AfxBeginThread((AFX_THREADPROC)BatchCollectionThread, (LPVOID)pCard); } But if I want to use some CString-like class object which is created in the thread, and because the thread open a dialogbox, it can't automativally return, void CMyDocument::OnTest() { AfxBeginThread(mythread, this); Sleep(1000); TerminateThread(); } UINT mythread(LPVOID lParam) { CString str_Tmp; str_Tmp =3D "I'm "; MessagBox(NULL,"a", "silly thread.", MB_OK); return(0); } Then I call TerminateThread() in main thread, it will leak some memory. =09 My question: How can I terminate a thread from outside when it can't response to message, so can't return by itself?=09 If there's some memory leap in every ExitThread/TerminateThread(), it'll hang after running 2~10 hours. James 3/23 >---------- >From: kevin@pln.com.tw[SMTP:kevin@pln.com.tw] >Sent: Monday, December 23, 1996 4:59 AM >To: 'mfc-l@netcom.com'; 'kvasilak@cyberoptics.com' >Subject: Re: Continuos data acquisition > > >You can create a structure that contains any data items you wanted >passing to the worker thread. > > CCardStruct* pCard =3D new CCardStruct; > pCard->m_bLaunchCardRecord =3D FALSE; > pCard->m_szBeginLunch =3D dlg.m_szTimeFrom; > pCard->m_szEndLunch =3D dlg.m_szTimeTo; > AfxBeginThread((AFX_THREADPROC)BatchCollectionThread, LPVOID)pCard); > > >Kevin Tarn >kevin@pln.com.tw > > >---------- >=B1H=A5=F3=AA=CC: = kvasilak@cyberoptics.com[SMTP:kvasilak@cyberoptics.com] >=B6=C7=B0e=A4=E9=B4=C1: 1996=A6~12=A4=EB19=A4=E9 PM 23:16 >=A6=AC=A5=F3=AA=CC: MFC-L@netcom.com >=A5D=A6=AE: Continuos data acquisition > > Environment: VC++ 4.1, Win 95 > =20 > =20 > I have an MFC app that needs to get data as fast as possible = during=20 > the life of the app. The app contains three OCX's one of which is = a=20 > graph on a DialogBar. I would like to call a function from within=20 > OnInitialUpdate() that just loops as fast as possible untill the=20 > program ends. However as we all know the user would be locked out = of=20 > the app, the UI would never update and the user could not close = the=20 > App. > =20 > The first, and easiest, solution was to use a OnTimer event to = allow=20 > some idletime processing to be done. This almost works, if the = timer=20 > interval is too short toolbars etc dont get updated, if the timer=20 > interval is too long the app runs too slow. This most problematic = when=20 > different machine speeds are involved. > =20 > The second solution was to add an OnIdle Loop to the timer, like = this, > =20 > LONG lIdle =3D 0; > while (AfxGetApp()->OnIdle(lIdle++)); > =20 > This allows the view to be updated but if a toolbar is moved I get = > this OS error, > =20 > "This application has performed an illegal operation and will be=20 > shutdown" > =20 > The debugger shows that this is totally within MFC code not mine, = Does=20 > anyone have a clue as to why calling OnIdle() from within a = OnTimer()=20 > would be bad? I got the OnIdle() idea from "Programming Windows95 = with=20 > MFC" by Prosie so I am surprised it doesn't work. > =20 > =20 > =20 > Solution three; > So now I bite the bullet and create a worker thread to handle the=20 > looping, this too almost works, Theproblem is that the thread = cannot=20 > get a handle to the Graph OCX that is on a DialogBar, The thread = can=20 > however get the handle if the Graph OCX is placed on the FormView = (=20 > not an option ) and I can get the Graph OCX's handle if I am = within=20 > the main thread, like OnTimer(). > =20 > the code to do this within the worker thread is; > =20 > UINT MyThread(LPVOID pParam ) > { > BOOL *Run =3D (BOOL *)pParam; > VARIANT vtRed, vtGreen, vtBlue; > CMultiApp *pMyApp =3D ((CMultiApp *)AfxGetApp()); > =20 > CCSGraph *MyGraph =3D pMyApp->m_MyDialogBar->GetChart(); > =20 > while(*Run) > { > pMyApp->m_ctlXPG.QuickGrab(nCamera, nTimeout, nInit); > pMyApp->m_ctlXPG.FetchFilterFrame(nNumLines, &vtRed,=20 > &vtGreen, &vtBlue); > =20 > pMyApp->m_Graph->SetPlotReadings( vtRed); > pMyApp->m_Graph->Refresh(); > } > =20 > m_MyDialogBar is a pointer to the DialogBar and is valid at the = time=20 > of the function call. > =20 > =20 > CCSGraph *CBarGraph::GetChart() > { > CCSGraph *pGraph =3D (CCSGraph *)GetDlgItem(IDC_CSGRAPHCTRL); > return pGraph; > } > =20 > GetDlgItem() Fails if GetChart() is called from the worker thread = but=20 > succeeds if called from the main thread. > =20 > =20 > =20 > The thread idea would be the preferred way to run this App, if it=20 > worked. > Any Ideas on how to get a pointer to that darn OCX? > =20 > Is there any other way to run this app without either a timer or a = > worker thread? > =20 > If someone can solve this I will nominate them the God of MFC :-) > =20 > =20 > Thanks, > =20 > Keith Vasilakes > Manufacturing Software Engineer, CyberOptics >
Mike Blaszczak -- mikeblas@nwlink.com Wednesday, March 26, 1997 At 17:53 3/24/97 +0800, mzsong@aztech.com.sg wrote: > Then I call TerminateThread() in main thread, it will leak some memory. You bet it will. You're lucky it doesn't crash your whole system, bring down your whole network, or format your hard drive. > How can I terminate a thread from outside when it can't response to >message, so can't return by itself? You can't. You need to let a thread die when it wants to die. If you want to write a program that uses threads, you need to make the threads able to exit on demand. That means you can't leave message boxes in your threads lying around. That means that you can't let your threads do things that could go into overtime without checking to see if they've been asked to terminate. Period. >If there's some memory leap in every ExitThread/TerminateThread(), >it'll hang after running 2~10 hours. That's on a _good_ day. On a bad day, it'll crash your machine on the first try. TerminateThread() is to be avoided at all costs. It's a bad API. It's not to be used. If someone on my team used TerminateThread() without discussing it wit hthe rest of the team for a week or two, they'd be out of a job. ExitThread() is unusable in threads that use MFC or the C Runtime libraries, period. .B ekiM http://www.nwlink.com/~mikeblas/ These words are my own. I do not speak on behalf of Microsoft. One is too many and a million is not enough.
mzsong@aztech.com.sg Friday, March 28, 1997 [Mini-digest: 2 responses] Hi, I don't think it's good to ask this question, because no WebMaster would like to find a lot of Automatically-Browser visiting his homepage and cause the network problem. Question: How to write a homepage downloader? If I use CWebBrowser control, it'll generate all kinds of messagebox. So I have to let the thread wait during the whole night, or close the poor thread from outside. It's a small toy, not a release requirment. James 3/28 This mesasge is my own. Nothing with our "respectfully" Aztech Co. or others. : | >---------- >From: Song Ming Zhang - R&D >Sent: Monday, March 24, 1997 1:53 AM >To: mfc-l@netcom.com >Cc: kevin@pln.com.tw >Subject: RE: Continuos data acquisition > >Hi, dear kevin and all mfc-member: > Now it's the last problem I can ask. > It's about use mfc object in a close-able thread. > > Kevin show the way to use mfc object in thread: > > class CMyDocument:public CDocumnet > { > public: > CString str_Thread_Tmp; > void OnTest(); > } > > void CMyDocument::OnTest() > { >> CCardStruct* pCard =3D new CCardStruct; >> pCard->m_bLaunchCardRecord =3D FALSE; >> pCard->m_szBeginLunch =3D str_Thread_Tmp; >> pCard->m_szEndLunch =3D dlg.m_szTimeTo; >> AfxBeginThread((AFX_THREADPROC)BatchCollectionThread, = (LPVOID)pCard); > } > > > But if I want to use some CString-like class object which is created = in >the thread, and because the thread open a dialogbox, it can't >automativally return, > > void CMyDocument::OnTest() > { > AfxBeginThread(mythread, this); > Sleep(1000); > TerminateThread(); > } > > UINT mythread(LPVOID lParam) > { > CString str_Tmp; > str_Tmp =3D "I'm "; > MessagBox(NULL,"a", "silly thread.", MB_OK); > return(0); > } > > Then I call TerminateThread() in main thread, it will leak some = memory. >=09 > My question: > How can I terminate a thread from outside when it can't response to >message, so can't return by itself?=09 > If there's some memory leap in every ExitThread/TerminateThread(), >it'll hang after running 2~10 hours. > James 3/23 > >>---------- >>From: kevin@pln.com.tw[SMTP:kevin@pln.com.tw] >>Sent: Monday, December 23, 1996 4:59 AM >>To: 'mfc-l@netcom.com'; 'kvasilak@cyberoptics.com' >>Subject: Re: Continuos data acquisition >> >> >>You can create a structure that contains any data items you wanted >>passing to the worker thread. >> >> CCardStruct* pCard =3D new CCardStruct; >> pCard->m_bLaunchCardRecord =3D FALSE; >> pCard->m_szBeginLunch =3D dlg.m_szTimeFrom; >> pCard->m_szEndLunch =3D dlg.m_szTimeTo; >> AfxBeginThread((AFX_THREADPROC)BatchCollectionThread, LPVOID)pCard); >> >> >>Kevin Tarn >>kevin@pln.com.tw >> >> >>---------- >>=B1H=A5=F3=AA=CC: = kvasilak@cyberoptics.com[SMTP:kvasilak@cyberoptics.com] >>=B6=C7=B0e=A4=E9=B4=C1: 1996=A6~12=A4=EB19=A4=E9 PM 23:16 >>=A6=AC=A5=F3=AA=CC: MFC-L@netcom.com >>=A5D=A6=AE: Continuos data acquisition >> >> Environment: VC++ 4.1, Win 95 >> =20 >> =20 >> I have an MFC app that needs to get data as fast as possible = during=20 >> the life of the app. The app contains three OCX's one of which is = a=20 >> graph on a DialogBar. I would like to call a function from within = >> OnInitialUpdate() that just loops as fast as possible untill the=20 >> program ends. However as we all know the user would be locked out = of=20 >> the app, the UI would never update and the user could not close = the=20 >> App. >> =20 >> The first, and easiest, solution was to use a OnTimer event to = allow=20 >> some idletime processing to be done. This almost works, if the = timer=20 >> interval is too short toolbars etc dont get updated, if the timer = >> interval is too long the app runs too slow. This most problematic = when=20 >> different machine speeds are involved. >> =20 >> The second solution was to add an OnIdle Loop to the timer, like = this, >> =20 >> LONG lIdle =3D 0; >> while (AfxGetApp()->OnIdle(lIdle++)); >> =20 >> This allows the view to be updated but if a toolbar is moved I = get=20 >> this OS error, >> =20 >> "This application has performed an illegal operation and will be=20 >> shutdown" >> =20 >> The debugger shows that this is totally within MFC code not mine, = Does=20 >> anyone have a clue as to why calling OnIdle() from within a = OnTimer()=20 >> would be bad? I got the OnIdle() idea from "Programming Windows95 = with=20 >> MFC" by Prosie so I am surprised it doesn't work. >> =20 >> =20 >> =20 >> Solution three; >> So now I bite the bullet and create a worker thread to handle the = >> looping, this too almost works, Theproblem is that the thread = cannot=20 >> get a handle to the Graph OCX that is on a DialogBar, The thread = can=20 >> however get the handle if the Graph OCX is placed on the FormView = (=20 >> not an option ) and I can get the Graph OCX's handle if I am = within=20 >> the main thread, like OnTimer(). >> =20 >> the code to do this within the worker thread is; >> =20 >> UINT MyThread(LPVOID pParam ) >> { >> BOOL *Run =3D (BOOL *)pParam; >> VARIANT vtRed, vtGreen, vtBlue; >> CMultiApp *pMyApp =3D ((CMultiApp *)AfxGetApp()); >> =20 >> CCSGraph *MyGraph =3D pMyApp->m_MyDialogBar->GetChart(); >> =20 >> while(*Run) >> { >> pMyApp->m_ctlXPG.QuickGrab(nCamera, nTimeout, nInit); >> pMyApp->m_ctlXPG.FetchFilterFrame(nNumLines, &vtRed,=20 >> &vtGreen, &vtBlue); >> =20 >> pMyApp->m_Graph->SetPlotReadings( vtRed); >> pMyApp->m_Graph->Refresh(); >> } >> =20 >> m_MyDialogBar is a pointer to the DialogBar and is valid at the = time=20 >> of the function call. >> =20 >> =20 >> CCSGraph *CBarGraph::GetChart() >> { >> CCSGraph *pGraph =3D (CCSGraph *)GetDlgItem(IDC_CSGRAPHCTRL); >> return pGraph; >> } >> =20 >> GetDlgItem() Fails if GetChart() is called from the worker thread = but=20 >> succeeds if called from the main thread. >> =20 >> =20 >> =20 >> The thread idea would be the preferred way to run this App, if it = >> worked. >> Any Ideas on how to get a pointer to that darn OCX? >> =20 >> Is there any other way to run this app without either a timer or = a=20 >> worker thread? >> =20 >> If someone can solve this I will nominate them the God of MFC :-) >> =20 >> =20 >> Thanks, >> =20 >> Keith Vasilakes >> Manufacturing Software Engineer, CyberOptics >> > -----From: Richard MorrisLook into the synchronization classes, particularly CEvent. You can easily use it as a way to signal a thread that it is time to shutdown, or do a number of other things. It will probably take a little restructuring of your threads, but then they will be well behaved. If your threads are doing much with the outside world, it is likely you need to use synchronization anyway. There is a good treatment of threads and synchronization in "Advanced Windows" by Jeffrey Richter (Microsoft Press). It doesn't discuss them in relation to MFC, but the leap is a very small one once you understand the APIs and their application. Good luck. At 12:38 AM 3/26/97 -0800, you wrote: >At 17:53 3/24/97 +0800, mzsong@aztech.com.sg wrote: > >> Then I call TerminateThread() in main thread, it will leak some memory. > >You bet it will. You're lucky it doesn't crash your whole system, bring >down your whole network, or format your hard drive. > >> How can I terminate a thread from outside when it can't response to >>message, so can't return by itself? ............. **************************************************************** Live now. Make now always the most precious time. Now will never come again. - Captain Jean-Luc Picard, U.S.S. Enterprise
Andrew L. Snow -- als@fl.net.au Sunday, March 30, 1997 At 10:01 AM 3/28/97 +0800, you wrote: > I don't think it's good to ask this question, because no WebMaster >would like to find a lot of Automatically-Browser visiting his homepage >and cause the network problem. Many have been written before... web whacker for instance. Oh well. > Question: How to write a homepage downloader? It can be written quite simply with Visual C++4.2's CInternetSession MFC class which has a useful ::OpenURL(..) function, which you can call to very easily call to open a CFile-type connection to an internet site (HTTP, FTP, or gopher I believe). It also has some kind of proxy support, see the visual C help for more info. All that remains is to parse the HTML for links- anchors and then follow them up. Hope that helps. ---- Andrew Snow als@fl.net.au
Become an MFC-L member | Вернуться в корень Архива |