// JP opened flex table

Click to See Complete Forum and Search --> : Multi-Threading Problem


fritzy
April 22nd, 2004, 03:08 AM
[NOTE: Posted this in the VC++ forum, but I realized I could prob get help here instead]

Hello Gurus :)

I am working on a project that requires multi-threading so that my user interface will respond while my application is doing the work...

I have something like this:

UINT workThread(LPVIOD param)
{
//** my work
...
return 0
}

and I am starting it via:

HWND hWnd = GetSafeHwnd();
AfxBeginThread(workThread, hWnd, THREAD_PRIORITY_NORMAL);

Now, the problem is... I need my work thread to interact with variables from my dialog implementation class (CMyAppDlg) but I can't seem to access them... I've tried a couple of things like

CMyAppDlg myDlg;
myDlg.m_strName.Format("Change this string");
UpdateData(FALSE);

and etc but they don't seem to work... I've never had to access variables from another class then the one I'm working in... I have also tried to make my 'workThread' in my main class(so it was defined as UINT CMyAppDlg::workThread(LPVOID param)) and I ran into alot of problems...

So in short, I need a solution for accessing variables in my dialog class from my worker thread, and everything I have tried has failed.

Please help:)

Regards,
Zak Farrington
:wave:

[EDIT]
Oh yes, I am using MSVC++ 6.0 for my IDE and the project is a MFC Dialog based application.

Andreas Masur
April 22nd, 2004, 03:40 AM
Well...in order to access dialog variables, you should pass the 'this' pointer of the dialog to the thread instead of the handle. However, as it looks like you rather want to update windows controls. In this case, you need to use user-defined messages as shown in the following FAQ (http://www.codeguru.com/forum/showthread.php?s=&threadid=231250)...

fritzy
April 22nd, 2004, 06:52 AM
Well I did that, but I'm still having problems...
I can do:

buffer.Format("%d", SomeInt);
::MessageBox(NULL, buffer, buffer, MB_OK);

that, and it will tell me the integer of Some Int...

but in my thread I have

CMyDlg *dlg = reinterpret_cast<CMyDlg*>(pvParam);
...
buffer.Format("%d", dlg->SomeInt);
::MessageBox(NULL, buffer, buffer, MB_OK);


But the messagebox will just tell me 0... how can I fix this??? This is what I am trying to do, correctly access(read and change) variables that are in CMyDlg from my worker thread.

Regards,
Zak Farrington
:wave:

Andreas Masur
April 22nd, 2004, 07:24 AM
Assuming that 'buffer' is a 'CString' local to your thread, and 'SomeInt' a member of the dialog class, the code should work.

fritzy
April 22nd, 2004, 08:33 AM
Thats exactly right, but it isnt working...

Andreas Masur
April 22nd, 2004, 05:33 PM
Can you post your project here (without the Debug and Release directory)?

fritzy
April 23rd, 2004, 02:36 AM
Well... I think I found the problem...

NOTE: SomeInt is set to 20


void CMyAppDlg::OnButton1()
{
CString buffer;
buffer.Format("%d", SomeInt);
::MessageBox(NULL, buffer, buffer, MB_OK);

//** set object handle for thread
HWND *dlg = new HWND;

//** Create Thread
m_pThread = AfxBeginThread(workThread, dlg);

if(m_pThread == NULL) //** Can't create thread
{
MessageBox("Could not create work thread!", "Error", MB_OK + MB_ICONINFORMATION);
EndDialog(0);
}
else
{
m_pThread->Run();
MessageBox("Thread running!");
}

}
}

Thats my event to start the worker thread... notice that dlg is just a 'new HWND'(I'm following the tutorials I've read, so I don't really know what I'm doing... Never worked with threads in my life, just thought I would say this so don't assume anything please :p)
(the message box shows the correct number outside the thread(20))
Now thats how I start my worker thread, now heres my actual thread

UINT CMyAppDlg::workThread(LPVOID pvParam)
{
CMyAppDlg *dlg = reinterpret_cast<CMyAppDlg*>(pvParam);
CString buffer;
buffer.Format("%d", dlg->SomeInt);
::MessageBox(NULL, buffer, buffer, MB_OK);

return 0;
}


Now theres my worker thread, which gives me the message box saying that SomeInt is 0...(when its set to 20)

I think the problem is how before I created my thread I am doing 'HWND *dlg = new HWND' but inside my thread I'm saying 'CMyApp *dlg = reinterpret_cast<CMyAppDlg*>(pvParam);'

I think thats what needs to be fixed but I'm not exactly sure what to do about it... if this is not the problem, I will post my source code.

Regards,
Zak Farrington
:wave:

fritzy
April 23rd, 2004, 03:08 AM
Okay I've ran into another problem... it keeps crashing for some reason... I've tried to debug but I lost my self lol(Sorry for being such a thread newbie :()

Anyways heres the source:

MrViggy
April 23rd, 2004, 12:38 PM
Instead of passing "dlg", pass the "this" pointer.

m_pThread = AfxBeginThread(workThread, this);

Right now, your passing a handle, which is not a 'CMyAppDlg' instance. Also, you're not initializing the handle to anything. So, whatever you do with the handle ('*dlg') is undefined.

Viggy

fritzy
April 23rd, 2004, 01:52 PM
TY!!! That solved the main problem... but now, any idea why its crashing? I've been trying to debug it again but still can't figure it out...... Only thing I get is Access Violation at 0xC0000005...

Maybe I'm not handling my thread correctly after its done working?

Regards,
Zak Farrington
:wave:

MikeAThon
April 23rd, 2004, 09:57 PM
Where precisely is your app crashing? Look at the call stack. Is it crashing somewhere within the call to ::MessagBox inside the thread?

I'm unsure about this, but looking at your code, the parent to ::MessageBox is defined as your app's main window. That's in another thread, which is generally not permitted (or, maybe, m_hWnd is not even defined for a dialog-based app -- I really don't know/remember).

One thing you can try is to define the parent as the desktop, by passing NULL into ::MessageBox: UINT CMyAppDlg::workThread(LPVOID pvParam)
{
CMyAppDlg *dlg = reinterpret_cast<CMyAppDlg*>(pvParam);

CWnd* myApp = FindWindow(NULL, "MyApp");

CString buffer;
buffer.Format("%d", dlg->SomeInt);

// don't do this ::MessageBox(myApp->m_hWnd, "SomeInt is set to " + buffer, "SomeInt inside of thread", MB_OK + MB_ICONINFORMATION);

// do this instead
::MessageBox(NULL, "SomeInt is set to " + buffer, "SomeInt inside of thread", MB_OK + MB_ICONINFORMATION);


return 0;
}

Another thing to check is to put a breakpoint right before the ::MessageBox and check the value of buffer. Does it show the correct value?

Mike

fritzy
April 24th, 2004, 01:00 AM
I don't think the problem is with the message box... because it always pops up plus I changed what you said and it still crashs... what ever is happening is happening after the MessageBox and I still don't know what it is :(

MrViggy
April 26th, 2004, 01:03 PM
What does the stack look like when it crashes? What line of your code is being executed?

Viggy

fritzy
April 27th, 2004, 11:03 AM
I'm not really sure... its right when the code its return 0;...

This is what my debug window says:

The thread 0xE87D1C51 has exited with code 0 (0x0).
Error: CWinThread::PumpMessage called when not permitted.


The thread exited, so whats this about PumpMessage?? :confused: Not permitted? Maybe I'm calling something after the threads exited?? I don't know I've looked the code and changed all kinds of things and the same thing happens :(


And heres you asked for the stack so heres straight from FAULTLOG with registers and etc etc:

Date 04/27/2004 Time 09:56
MYAPP caused an exception 03H in module MFC42D.DLL at 017f:5f43976c.
Registers:
EAX=00000001 CS=017f EIP=5f43976c EFLGS=00200202
EBX=0064f968 SS=0187 ESP=0064f55c EBP=0064f56c
ECX=10261558 DS=0187 ESI=0064f598 FS=2747
EDX=80007d88 ES=0187 EDI=0064f5f8 GS=0000
Bytes at CS:EIP:
33 d2 85 d2 75 dd a1 e8 e0 4c 5f 83 e0 02 85 c0
Stack dump:
0064f5f8 0064f598 0064f968 00771db0 0064f590 5f438e20 0064f5f8 0064f598 0064f968 00000000 00771db0 00000000 00000001 0064f604 00401ede 0064f8a4


Hope you can help me :(

Regards,
Zak Farrington
:wave:

MrViggy
April 27th, 2004, 12:47 PM
I'm assuming Visual Studio of some sort? Open the "Call Stack" debug window (In Visual Studio 7.x; while debugging; "Debug"->"Windows"->"Call Stack").

The debug window you pasted is the output, and it's telling you that a thread exited, and then a call to "PumpMessage" was made. According to the debug output, it looks like only one thread exited (most likely the one that had the crash). Other threads are still executing, hence the error message about PumpMessage.

The fault log is no help. There's nothing in there that would make sence to me (as I don't have your code/app etc.).

Viggy

MikeAThon
April 27th, 2004, 03:11 PM
Odd. Your call to AfxBeginThread() starts a pure worker thread, which means your thread does not have a message pump. So that means that the call to CWinThread::PumpMessage must be occurring in the main thread. It's puzzling why that would be "not permitted".

Try replacing your call to ::MessageBox in the thread with a simple "TRACE" output to the debug window. (You really didn't need MessageBox anyway, did you? You just needed a way to verify that you had correctly located the value to SomeInt from the dlg, right?) My thinking here is that MessageBox as a Windows-generated dialog must be running some sort of a message pump, and that this is the message pump that's somehow causing the "not permitted" call to CWinThread::PumpMessage.

Let us know.

-Mike

//JP added flex table