|
Your asking for trouble even thinking of calling TerminateThread. Here's an example program which shows the kind of thing that can go wrong:
------------------------------------------
#include <windows.h>
CRITICAL_SECTION g_cs;
void ShowMessageBox()
{
EnterCriticalSection(&g_cs);
MessageBox(NULL, "Hello", "ShowMessageBox", MB_OK);
LeaveCriticalSection(&g_cs);
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
ShowMessageBox();
return 0;
}
int main(int argc, char* argv[])
{
InitializeCriticalSection(&g_cs);
// Start thread.
DWORD ThreadID;
HANDLE hThread = CreateThread(NULL, 0, &ThreadProc, 0, 0, &ThreadID);
// Wait for one second then kill the thread.
// It still holds the CRITICAL_SECTION!!!
Sleep(1000);
TerminateThread(hThread, 0);
// We've killed the "ShowMessageBox" API, permanently, calling it now
// causes this thread to dead lock!
ShowMessageBox();
DeleteCriticalSection(&g_cs);
return 0;
}
------------------------------------------
In this program calling TerminateThread permanently breaks ShowMessageBox because we killed the thread when it still held a lock. This is the worst kind of bug as it's very hard to reproduce as it's sensitive to timing. If you're calling Win32 functions many of them will briefly hold locks, if you terminate a thread while it is holding one you're screwed.
Moral: Don't call TerminateThread. There are exceptions but very few.
The only real safe way to terminate a thread from another thread is to ask it nicely. This generally involves signaling an event and then waiting on the thread handle.
Steve
|
|
|
|
|
Absolutely, there are plenty of trouble with this function that is why I suggested avoiding it. It seems to me though that Aqueel wanted something like this asking
[quote]to terminate a thread from another function not in the thread function itself[/quote].
So, he does not seem to want to terminate the thread from "inside" for whatever reason.
|
|
|
|
|
I understand that you suggested he avoid it. I just wanted to clarify the dangers as in general if you use TerminateThread then it is a case of the cure being worse then the disease.
Steve
|
|
|
|
|
Can he want to use it for debug purposes? Say, when his other thread freezes, does not exit properly, stops processing messages, then it may be OK to use it to terminate the other thread and print a status info?
BTW, thanks for the code. For my notes I should keep your example as another reason to avoid it.
|
|
|
|
|
There may be times when you have little choice, so I guess the answer is yes. That said if the thread froze while holding a lock you've got a problem - But if this is the case you've got a problem anyway as it's frozen so I guess you're not making anything any worse. In general once you've terminated a thread the state of the whole process is suspect.
Steve
|
|
|
|
|
When using a CWinThread object it is simple to terminate a thread.
1. if you have pointer to the object you can use:
CMyWinThread* pThread;
pThread->PostThreadMessage(WM_QUIT, NULL, NULL) This will cause the thread, when idle to stop.
The thread will go to the ExitInstance function where the clean up can begin.
2. if you don't have a pointer to the object but you have the Thread Id, you can use:
DWORD dwThreadId;
::PostThreadMessage(dwThreadId, WM_QUIT, NULL, NULL); With the same results
3. if you have neigther you need to have a common object to signal the thread to stop. This object
must be protected by thread synchronisation objects (like CMutex, CCriticalSection) or you can use
the CEvent to signal the thread to stop. I prefer one of the first two solutions because you don't
need to have a polling mechanisme to check if you need to stop or not. The third solution is preffered when the thread needs to be stopped during a lengthy operetation.
codito ergo sum
|
|
|
|
|
Hi, someone has PM'med me but I can't sent a reply, so i will answer here.
Barry wrote: I have a situation where I have a user interface thread that is opening a dialog with a progress dialog that is used to show progress on processing going on in the parent thread. The underlying dialog is wrapped in a thread-safe class so messages to the dialog are handled properly. When processing in the parent thread is complete the dialog is gracefully shut down. If the dialog is being moved around when the parent thread tries to shut the thread down by posting a WM_QUIT method to the thread, the ExitInstance method in the CWinThread-derived class used to handle the thread never gets invoked and the thread remains active. I also tried to add a user-defined message with a message handler but the message handler never got invoked when the parent thread sent the message to the thread. Any clues?
I have created a simular test version an can confirm the same error.
I have browsed to the MFC source and have found the problem I have found a solution probably on of the worst in oo design but what the heck if even MFC isn't working like it should
First let me explain what happens.
I have a DLG(main) application wich creates a thread. This thread creates a Modless dlg and closes it on exiting the thread.
The main applaction sends a m_pCloseThread->PostThreadMessage(WM_QUIT,0,0);
To let the thread exit.
This works like intended as long as the dlg in the thread doesn't get moved.
The normal WM_QUIT is getting processed in CWinthread::Run function
...
if (!PumpMessage())
return ExitInstance();
..
But when you move over the window with you mouse the messages of your movement should be redirected to the Message loop of the dialog.
If you click and hold down the left mouse button (in order to drag, but not nessacary) the full message handling is done by the DLG message loop. The thread message loop never gets called any more until you leave the mousebutton. The posted WM_QUIT message isn't processed by the thread message loop (let me call this the parent loop) but by another loop, this loop (child) probably see that the message isn't for him and neglects it.
The parent loop doesn't know anything of that message. I believe it’s a design flaw in the MFC, but this is just my 2 cents :P
I hope that I explained it correctly.
But how do we solve this Design-flaw: Like I said before I have done it Quick and dirty.
1. I've added a Boolean member in the dialog to notify the thread that There was a WM_QUIT sent
2. In the dialog I need to capture a WM_QUIT message. This is done by overriding the WindowProc function (child loop)
LRESULT CClosingInfo::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_QUIT)
{
m_bOopsImDead = true;
}
return CDialog::WindowProc(message, wParam, lParam);
}
3. I also need to override the thread loop (parent) which is in the CWinthread::run function.
The code inside the function can be found in the thrdcore.cpp file of the MFC source codes
int CCloseTrhread::Run()
{
ASSERT_VALID(this);
_AFX_THREAD_STATE* pState = AfxGetThreadState();
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
for (;; )
{
while (bIdle &&
!::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
{
if (!OnIdle(lIdleCount++))
bIdle = FALSE;
}
do
{
if (!PumpMessage())
return ExitInstance();
if (IsIdleMessage(&(pState->m_msgCur)))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
if(m_pCloseWindow->m_bOopsImDead)
{
return ExitInstance();
}
}
}
4. Now instead of calling the thread to close, call the dlg
<code>m_pCloseThread->m_pCloseWindow->PostMessage(WM_QUIT, 0 ,0);
This works also when no one is dragging or holding the dialog.
Hope that this helps, or at least sets you on its way.
Let me know
Kurt Pattyn
codito ergo sum
-- modified at 18:52 Thursday 25th May, 2006
|
|
|
|
|
Thank you friends!
Specially BadKarma! You solved my problem.
We Believe in Excellence
-- modified at 23:34 Friday 17th February, 2006
|
|
|
|
|
Aqueel wrote: I am using CWinThread for threading in MFC. I want to terminate a thread from another function not in the thread function itself. Can i do that?
http://www.flounder.com/workerthreads.htm
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
cheers,
Alok Gupta
VC Forum Q&A :- I/ IV
|
|
|
|
|
pDC->GetSafeHdc(); It will return a pointer to the existing memory or allocate the memory and then return the pointer to this allocated memory.
OR
how i can release this memory
|
|
|
|
|
GetSafeHdc() does not return a pointer. It returns the handle of the device context - you don't need to "release" it.
Ryan "Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
|
|
|
|
|
It returns a handle to an exiting HDC or NULL. If you single step through the code you will see that calling GetSafeHdc() is equivalent to return(hdc?hdc:NULL), which is kind of silly if you ask me. Because if the test codition faile "hdc?" then the hdc is already equivalent to NULL. The long and the short of it is that GetSafeHdc() does not allocate any memory, it just makes sure that the HDC returned is either valid or NULL.
INTP
Every thing is relative...
|
|
|
|
|
anilksingh wrote: pDC->GetSafeHdc();
just return the reference to selected DC.. the CDC it self manage life cycle of the HDC object.. so you don't need to worry about it.
Secondly you can use DeleteDC api to delete DC
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
cheers,
Alok Gupta
VC Forum Q&A :- I/ IV
|
|
|
|
|
Hi All.
I want to write some code that have some method that in create bitmap of the current screen.
What i mean is when this method is call - there will be create file in name X.bmp that contain the info of the screen ( line pressing on PrtScn button ).
How can i catch the picture ? what windows method (maybe API function) i need to use ?
|
|
|
|
|
You may want to look up PrintWindow and WM_PRINT . There are many other techniques, which you choose depends on what OSs you need to support.
Steve
|
|
|
|
|
I will not explane how it is done, but I suggest searching using the keywords "screen capture". There are lots of Web articles on the subject, and there is probably still a code sample in the MSDN somewhere (the origanal example is probably 15 years old now). I believe there are a few articles at CP on the subject.
INTP
Every thing is relative...
|
|
|
|
|
|
#import "msxml3.dll" rename_namespace ("NEW_MSXML2")<br />
using namespace NEW_MSXML2; <br />
#import "MSSOAP30.dll" exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME") rename_namespace ("NEW_MSSOAPLib30")<br />
using namespace NEW_MSSOAPLib30;
In Debug mode, it creates MSSOAP30.tli and MSSOAP30.tlh files which has NEW_MSXML2 parameter,but in Release mode those two files are getting created with MSXML2 parameter.
Any Idea whats happening?
cheers,
Super
------------------------------------------
Too much of good is bad,mix some evil in it
|
|
|
|
|
super wrote: In Debug mode, it creates MSSOAP30.tli and MSSOAP30.tlh files which has NEW_MSXML2 parameter,but in Release mode those two files are getting created with MSXML2 parameter.
Better post this problem in Microsoft newsgroup!
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
cheers,
Alok Gupta
VC Forum Q&A :- I/ IV
|
|
|
|
|
What if it is some sort of preprocessor issue. I think using the "NEW_" in your new name space name could be causing a problem.
If you called it the "123123_" namespace instead, does that work?
I have seen DUMBER issues than this with preprocessors before. I am leary of calling ANYTHING "NEW" these days, since that seems to be the magic keyword ever since C++ came out
People that start writing code immediately are programmers (or hackers), people that ask questions first are Software Engineers - Graham Shanks
|
|
|
|
|
Hi,
Can I write a shell extension which can process my own shell format?
For example: I have an application which has own data format, and when
drag from this applicaion and drop on explorer, the extension can process this data format.
It's like when you drag some texts and drop on explorer, which generate some special file.
Of course, I want generate my own files.
Anyone can help me?
|
|
|
|
|
How do I dynamically create a button (for example).
I understand how to create a button in code
ie CButton pBut* = new CButton()
pBut->Create( ..... )
but how do I trap when the button is pressed? I can't add entries to the message map because at design time the button doesnt exist?
TIA
|
|
|
|
|
you should overide the OnCommand function. The HIWORD of the wParam contains the action and the LOWAORD of wParama contains the Id of control
nav
|
|
|
|
|
For handling the evenmts on the buttons:
You have to override onCommand method and then in this you can check the id and perform the operations:
In onCommand:
you can get the id in LOWORD(wParam).
Check this and write the code in the following loop.
Cheers
Ganesh
|
|
|
|
|
The last argumen of button.Create is button id. You can use it in message map
CButton *pButton = new CButton;
pButton.Create(WS_VISIBLE|WS_CHILD,CRect(10,10,110,30),this,1 /*Id of the button any id which is unique*/ );
void OnHandler(void)
{
// Something
}
ON_BN_CLICKED(1 /* Last argument of create */,OnHandler)
MANISH RASTOGI
|
|
|
|