|
I am doing some OpenGL drawing in MFC view.
I have a OpenGL class which is used as the base class for MFC view. Then using display lists i have tried to put the drawing on the view. But in tha case of huge point sets, the View doest respond because of openGL drawing.
Then i thought of using threads for openGL.Now i want to implement a thread for drawing openGL stuff.
I have one static UINT threadfunc(LPVOID param) and void threadfunc() declared.
Then i have tried to begin the thread.
I did not get any compilation, linker errors.
But i was unsuccessful in getting the drawing stuff.
Can anyone help me?
|
|
|
|
|
This is a slight different question than the previous memory leak one. I have converted the demo project to Visual studio 7.1 and compiled it under the debug mode, and this is what I get when I clicked on "Start" to run the thread.
ThreadDemo.exe': Loaded 'C:\Program Files\Yahoo!\Messenger\msvcr71.dll', No symbols loaded.
Detected memory leaks!
Dumping objects ->
thrdcore.cpp(311) : {78} client block at 0x00326A50, subtype c0, 68 bytes long.
a CWinThread object at $00326A50, 68 bytes long
c:\code\thread2\threaddemo\threaddemodlg.cpp(196) : {77} normal block at 0x00324B80, 4 bytes long.
Data: < > E8 FD 12 00
Object dump complete.
The thread 'Win32 Thread' (0xdb4) has exited with code 0 (0x0).
The program '[3796] ThreadDemo.exe: Native' has exited with code 0 (0x0).
------------------------------------
This is very confusing. Please help
jiac
|
|
|
|
|
Your idea had saved my ass.
I use it for multithread receives with sockets.
THANKS, man.
|
|
|
|
|
Hi Enis,
Thank you so much for this little technique. I've found it very useful indeed. However, I've hit one problem which is that no matter how hard I try I can't avoid getting a memory leak when I run it.
The leak is always 4 bytes long and I'm convinced it's the THREADSTRUCT. I've tried to delete it but have found it virtually impossible to get rid of.
How and where do you delete this object? Can you help?
Many thanks,
Simon
|
|
|
|
|
Can't you just delete ts structure within the StartThread function; this seems logical since ts points to the memory space that was allocated.
-- Darin
|
|
|
|
|
Add "Delete ts;",Before "return 1;",It Should Be Solve Memory Leak Problem.
|
|
|
|
|
Thanks a lot. Your article really got me out of a fix. I have though 1 problem. I have a class X that instantiates a class CSerialPort (freeware).
I am spawning a thread so that I can wait for a COM event. I tried WaitEvent like so
ts->this->m_Port.WaitEvent(dwMask);
it is exceptioning at this point. Could someone tell me why that is happening and what I could do about it?
Thanks
|
|
|
|
|
hey
Tell me please how to stop the thread in between from some button click event.
I am using pThread->SuspendThread()
Thread is stopped but when i return to my Main form program hangs.
Thanks
Shailesh
|
|
|
|
|
Hy,
I didn't test the exact code you wrote in your previous post, but I can sugest you a solution using Events. (the code below is typed so it might not be such accurate)
HANDLE yourEvent;
yourEvent = ::CreateEvent (NULL,
TRUE,
FALSE,
NULL
);
CWinThread* pWorkerThread = NULL;
pWorkerThread = AfxBeginThread (ThreadFunc, ...);
pWorkerThread->m_bAutoDelete = FALSE;
if (::WaitForSingleObject (pWorkerThread->m_hThread, INFINITE) == WAIT_OBJECT_0)
if (pWorkerThread != NULL)
::GetExitCodeThread (pWorkerThread->m_hThread, &dwExitCode);
CloseHandle(yourEvent);
delete pWorkerThread;
I hope this helps.
You can also check Joseph M. Newcomer's great articles about threads
(http://www.codeproject.com/threads/usingworkerthreads.asp[^])
Enis Arif
-----------
"I am enough of an artist to draw freely upon my imagination. Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world." (Albert Einstein)
|
|
|
|
|
From PEPE2207
Hi, Enis, Recently I tried your threaddemo article and I found it works fine, but I am a bit confuse because I can not discover where is deleted the _param pointer releasing the heap memory asigned to the ts THEADSTRUCT instance that you were using the new istruction. Sincerely
|
|
|
|
|
Hey I am using this code in my thread as
void CUploadForm::OnButtonUpload()
{
THREADSTRUCT *_param = new THREADSTRUCT;
_param->_this = this;
pThread = AfxBeginThread (StartThread,_param );
}
UINT CUploadForm::StartThread (LPVOID param)
{
THREADSTRUCT* ts = (THREADSTRUCT*)param;
ts->_this->PreparePostData();
AfxEndThread(0);// here
return 1;
}
Now i want to stop this thread process on some button click event but when return to my form my program hangs. I am stopping as:
void CUploadForm::OnButtonCancel()
{
if(pThread)
{
pThread->m_bAutoDelete = FALSE;
UINT aa = pThread->SuspendThread( );
SetDlgItemText(IDC_EDIT_RESPONSE,_T("Process Stopped by user."));
pThread = NULL;
}
}
and when i press the button to return to my main program it hangs any idea
void CUploadForm::OnButtonReturn()
{
CMainFrame* pFrame = (CMainFrame*)GetParentFrame();
pFrame->SwitchToForm(IDD_NOPDCITATION_FORM);
pFrame->SetWindowText(_T("Cite Capture"));
}
Please help me
shailesh
|
|
|
|
|
I used this example and it works fine if i do it exactly like he has. But what if i actually want to do something inside the thread. I can't.
I have member control called m_ball1 and a HICON called m_h0;
I want to update the m_ball1 within the thread but i can't.
i keep getting the error
error C2228: left of '.SetIcon' must have class/struct/union type
error C2597: illegal reference to data member 'CCash3mfcDlg::m_h0' in a static member function
I have everything exactly like the author of this demo has except my Classname is different I used CCash3mfcDlg.
I have this in the cpp. If i // it out the program works just like the demo.
What am I doing wrong cause i would really like to incorporate this into my program.
UINT CCash3mfcDlg::StartThread(LPVOID param)
{
THREADSTRUCT* ts = (THREADSTRUCT*)param;
//here is the time-consuming process which interacts with your dialog
AfxMessageBox ("Thread is started!");
ts->_this->m_processstatus.SetRange (0, 1000);
while (ts->_this->m_processstatus.GetPos () < 10000000)
{
Sleep(500);
////////////////////THE MENTIONED ERRORS ARE CAUSED BY THIS ADDITION////////
m_ball1.SetIcon(m_h0);
////////////////////////////////////////////////////////////////////////////
ts->_this->m_processstatus.StepIt ();
}
//you can also call AfxEndThread() here
return 1;
}
Just starting to get into Visual C++ so give me some slack please.
|
|
|
|
|
I am just guessing here, based on my own challenges with multi-thread, but perhaps it will help you (?)
The multi thread functions must be static, and there are restrictions on the kinds of access static functons can have. I am guessing m_h0 is not static and therefore not directly acessible by the static multi thread func.
Basically a static function (and static variables) only exists once in memory, regardless of the number of times you instantiate an object from a class. This means a static function cannot know about the specific instance of an object and ita members (at least not directly.
I.e. if class CTest has member NotStatic, and static member Static, then
CTest T1;
CTest T2;
T1.NotStatic = 1;
T2.NotStatic = 2;
ASSERT( T1.NotStatic != T2.NotStatic ); //ok, no conflict
T1.Static = 1; //Static now 1
T2.Static = 2; //Static of ALL CTests now 2!!!
ASSERT( T1.Static != T2.Static ); //FAILS - CTest.Static all the same veriable.
A static function in CTest using NonStatic, would not directly know which instance (T1 or T2) to use, and therefore fails.
However, if you somehow pass the static function enough info to resolve the referencing (usually by a this pointer), you are ok.
Therefore you might try referencing m_h0 using the _this pointer - as far as I can see the THREADSTRUCT includes a _this pointer, which would let the static function access the specific instance of CCash3mfcDlg which holds the specific instance of m_h0. I am guessing the m_ball1 is also non static.
//m_ball1.SetIcon(m_h0); changed to use this pointer
ts->_this->m_ball1.SetIcon(ts->_this->m_h0);
Nitpicking: Why set the icon in a thread, rather than before calling thread in an initialize function? If you have to do it you should probably have a function
CCash3mfcDlg::SetIcon() {
m_ball1.SetIcon(m_h0);
}
and call it from your thread like this
ts->_this->SetIcon();
PS If you are just learning C++, you might want to start easier than multi threading , but good luck, I admire your courage.
|
|
|
|
|
Thanks for your help and encouragement on the project. I actually completed it. You were right about the static pass in the thread. here is what i did.
And as for the setting of the icon I did that for a specific reason. Maybe not the most suffient at the time but I am still learning. I have 3 icons on the screen to represent balls from 0 to 9 and i randomly generate a number sequence consisting of three numbers while the thread runs. and it displays that number sequence represented as balls. and I run it in the thread so it makes the balls look as if they are spinning.
here is a portion of the source pertaining to the thread.
http://rafb.net/paste/results/rx590089.html
Thanks again,
Win32newb
"Making windows programs worse than they already are"
|
|
|
|
|
Glad I could help
BTW, the link http://rafb.net/paste/results/rx590089.html does not seem to work
As for my nitpick about setting icons, please ignore that.
If you are trying to do sprite like animation (using icons because they can have transparency) running the "frames" from a worker thread seems like a good solution (IMO).
Jens
|
|
|
|
|
It was my understanding that you should not pass pointers to CWnd objects like dialogs into threads, but pass the handle (using GetSafeHwnd), and then retrieve pointer in thread using CWnd* pWnd = CWnd::FromHandle(pParam).
But, I might be wrong - I am here becuse the examples showing the above does not seem to work for me when trying to give me access to a dialog from within a thread
(the returned pointer seems to point to some other uninitialized instance)
If anyone knows about this I would love to hear from you....please?
Example: CMyDlg:CDialog has member variable int m_iX = 5424992;
CMyDlg::OnBtnGo{) {
...
AfxBeginThread(MyProcc, this->AfxGetSafeHwnd())
...
}
UINT MyProcc(LPVOID pParam) {
CMyDlg* pDlg = (CMyDlg*)(CWnd::FromHandlePermanent((HWND)pParam));
TRACE1("X=%i", pDlg->m_iX;
}
results in 4258440 not 5424992 ?????
Incidentally, pDlg != this pointer in dlg,
but pParam = m_hWnd of dialog
Arrgghhhhh!!!
Any help on HOW I can access a member in MuDlg from a thread would be appreciated.
Jens
|
|
|
|
|
Correction: AfxBeginThread(MyProcc, this->GetSafeHwnd()) NOT AfxBeginThread(MyProcc, this->AfxGetSafeHwnd())
Sorry about that
|
|
|
|
|
As others have noted, when using threads one might get an assertion if passing objects by pointers. Specifically in Wincore.cpp line 886:
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
I still have no sucess passing access to my dialog using the handle - I seem to get a pointer to something uninitialized.
However, I did have better success acessing things in the dialog when I stopped using the handle, and returned to using the this pointer AND allocated the member objects I want on the heap using "new" command (or is that the stack? I don't remember right now) during my dialogs initialization.
I have no idea if this is "safe", or just avoids the MFC asserts letting me run the code. It seems to work though, but if anyone knows if this is the "proper" and safe way to do it, please post!
Anyway, if you have problems getting pointers to stuff into your threads, try allocating them with new.
I admit that by know I am completely confused
I really had the impression that objects to threads should be passed as handles, but...
Jens
|
|
|
|
|
Something on Multithread programming in VC 6 online help under Multithreading: Programming Tips
Accessing Objects from Multiple Threads
For size and performance reasons, MFC objects are not thread-safe at the object level, only at the class level. This means that you can have two separate threads manipulating two different CString objects, but not two threads manipulating the same CString object. If you absolutely must have multiple threads manipulating the same object, protect such access with appropriate Win32 synchronization mechanisms, such as critical sections. For more information on critical sections and other related objects, see Synchronization in the Win32 SDK.
The class library uses critical sections internally to protect global data structures, such as those used by the debug memory allocation.
Basically, CWnd objects only exist in the threads that they are created in, so passing window classes by handle and casting them does not cause the variables you defined in the derived window classes to be passed over, you are actually creating a new object pointing to the same window handle.
For me, I usually encapsulate my data members in a separate object/structure and pass the pointer to that object/structure.
The alternative is to pass the window classes by pointer and use mutexes to coordinate the access to the data members. It is more risky though because the OS itself is also access your window pointer to perform management functionality such as redraw etc.
|
|
|
|
|
"...you are actually creating a new object pointing to the same window handle"
That was what I assumed was happening, thanks for confirming that.
What I ended up doing was using a Functor. Basically a simple template class that takes a pointer to an object and a pointer to a function in the object, and then has a function call to execute using the pointers.
The Function Pointer site has some excellent explanation of function pointers, Functors, etc. I highly recommend it:
http://www.function-pointer.org/index.html
This aproach allows me to pass the Functor to a static UINT ThreadRun(pFunctor) function I can call from AfxBeginThread, and ThreadRun then uses Functor to run the function I really want to run, in the object I want to run it in (obviously with critical sections as appropriate for multi-thread).
As far as I can tell (but I am just learning this), the Functor class is the "approved" approach to accomplish what the author of this article tried with his structure, but being a template class it is more generic, and having a destructor prevents memory leaks if used correctly)
This has been quite a learning experirnce for me - perhaps this thread will help the next programmer who is trying this.
Jens Winslow
|
|
|
|
|
... great idea
Maybe I will update the article in the near future.
Enis Arif
-----------
"I am enough of an artist to draw freely upon my imagination. Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world." (Albert Einstein)
|
|
|
|
|
Thanks, but I really can't take much credit. I just did as Lars Haendel suggested on his site.
Jens Winslow
|
|
|
|
|
It occurred to me that people might wonder why I choose the more complicated use of a Functor instead of just using a structure with a this pointer and data parameters (now that I am done, I wonder too).
Let me share with you a tale of mystery and wonder - a tale of a painful journey!
First I did try passing a pointer to a structure...
In my first structure based approach I defined a structure and enumerator to pass to a static UINT Command_T( LPVOID pCmdFunctor) which I could call from AfxBeginThread.
<br />
enum EChanCmd {<br />
INITIALIZE,<br />
SERVERCONNECT,<br />
CLIENTCONNECT,<br />
SEND,<br />
RECEIVE,<br />
CANCEL<br />
};<br />
<br />
struct SChanCmd {<br />
CMuxChannel* pChan;<br />
SMuxChannelEventData* pParam;<br />
EChanCmd eCmd;<br />
}<br />
Command_T is a switch statement that then calls the appropriate command function in the CMuxChannel object pointed to by pChan. For debugging I used a TRACE before and after the call, calling pChan->GetStatus(), a member function created to tell me the status .
At first things seemed to work fine . It was a bit of a pain to declare SChanCmd every time I wanted to issue a command with a worker thread, making for slightly complicated code like:
<br />
SChanCmd uCmd;<br />
uCmd.pParam = new SMuxChannelEventData;
uCmd.pParam->wp = (WPARAM)(USHORT)m_uiPortNum;<br />
uCmd.pParam->lp = (LPARAM)(LPCTSTR)m_strIPAddr;<br />
uCmd.eCmd = CMuxChannel::CLIENTCONNECT;
uCmd.pChan = &m_Chan;<br />
AfxBeginThread(CMuxChannel::Command_T, &uCmd);<br />
Add to this a large ugly switch statement in Command_T, and my code was esteticaly not to pleasing. But after 3 days of battling with it I did not care!
Then I hit a minor snag.
Some of my CMuxChannel commands might throw an exception (which are appropriately handled in the class). To my surprise, if an exception occurs my uCmd->pChan is set to NULL!!!! God only knows what else may be happening! I am guessing that the unwinding of the heap / stack occurring during a throw/catch exception somehow blows away my pointer (I tried saving a backup and using it, but that did not work).
What ever is happening made me very nervous about the condition of m_Chan, and my ability to call functions from AfxBeginThread.
I then tried using the Functor template (see link above), but I was not quite able to get it working, so I created my own less generic functor specifically for CMuxChannel. The concept was simple:
A class with a pointer to an instance of CMuxChannel, a function pointer to a command function in CMuxChannel, and a pointer to the parameter. Add a Call function to do the call, and a constructor taking a pointer to CMuxChannel and the desired function, and BINGO!
Now I can call my function like this, which looks a lot better:
<br />
CMuxChannel::CCmdFunctor uCmd(&m_Chan, CMuxChannel::ConnectAsClient);<br />
AfxBeginThread(CMuxChannel::Command_T, &uCmd);<br />
In reality the syntax for my Functor was murder to get right (had I known I would not have bothered, and just wrapped each command function in a static UINT AfxBeginThread function) But I did get it working at last.
<br />
class CCmdFunctor {<br />
public:<br />
CCmdFunctor(CMuxChannel* pChan, void (CMuxChannel::*ptrCmdFunc)(SMuxChannelEventData*), SMuxChannelEventData* pParam = NULL);<br />
<br />
void Call() { (*m_pChan.*m_ptrCmdFunc)(m_pParam);}<br />
<br />
CMuxChannel* m_pChan;
private:<br />
<br />
void (CMuxChannel::*m_ptrCmdFunc)(SMuxChannelEventData*);<br />
SMuxChannelEventData* m_pParam;<br />
};<br />
<br />
static UINT Command_T( LPVOID pCmdFunctor);
In conclusion:
1) Functors, multi-threaded, and function pointers are not for the faint of heart!
2) Something strange happens to your pointers to objects if the object uses / throws exceptions internally (feel free to explain this if you can)
3) Why did I ever want to become a programmer anyway?
Perhaps this will help someone else (I hope)
Me, I am thinking about becoming a farmer
Perhaps this was not a good day to code after all;P
Jens Winslow
|
|
|
|
|
I had a rather nasty surprice...
Since the functor is called by AfxBeginThread, we must be carefull that Functor does not go out of scope before AfxBeginThread has called the Call function, or nasty things happen, like access violations and other randomness
My solution: create Functor on heap with new
pCmd = new CMuxChannel::CCmdFunctor(&m_Chan, CMuxChannel::ConnectAsServer);
and have my Command_T function responsible for deleting it, when thread exits and we presumably are done with info in Functor)
UINT CMuxChannel::Command_T( LPVOID pCmdFunctor )<br />
{<br />
CCmdFunctor* p = (CCmdFunctor*)pCmdFunctor;<br />
CString str = p->GetChan()->GetState();<br />
p->Call();<br />
delete p;
str = str + " -> " + p->GetChan()->GetState();<br />
TRACE1("\nSM: %s ",str); <br />
return 0;<br />
}
Jens Winslow
|
|
|
|
|
|