Click to See Complete Forum and Search --> : killing thread


young1
November 11th, 2004, 02:44 PM
I have a program will creating a thread whenever it a MSG related to it occurs. the program will have a lot of these kinds MSG, so do you think it will creat many thread, or just the same one. if is is causing many thread, how could i kill them after using it.

TSYS
November 11th, 2004, 02:49 PM
From your description, I expect it will generate many threads. The alternative is to create a thread, then send the messages to it as they occur.

In any event, the best way to terminate a thread is to somehow - like with a message - notify it to terminate itself.

young1
November 11th, 2004, 02:52 PM
thank you, how to send a msg to it when a event occured?

chi_luci
November 11th, 2004, 02:53 PM
you can kill them only by posting a message WM_CLOSE and handle that message in your thread. The number of threads depends of your needs but I suggest only one thread if you don't have need of so many (because else you might need to do of some syncronisation between threads ). Simply do something like :

UINT threadFunc( LPVOID lp )
{
DWORD dwThreadID = GetCurrentThreadId();//do something with this id.. use it to post messages to this thread
BOOL bRet = FALSE;
MSG msg ;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE) ; // Force to make the queue
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
switch( msg.message )
{
case WM_CLOSE:
{
return -1;
}
break;
}
}
return 1;
}

chi_luci
November 11th, 2004, 03:01 PM
send messages to thread via

PostThreadMessage( threadID, msg, wParam, lParam )

young1
November 11th, 2004, 03:07 PM
Is able to directly call the thread function? like threadFunc(lp)?

chi_luci
November 11th, 2004, 03:15 PM
I guess you wanted to ask how to start a thread.. :wave:
Use:

AfxBeginThread( threadFunc, (LPVOID)pParam );
//pParam = parameter too pass to the thread at creation time


you cannot directly call this thread function because it must use a queue to process messages..

young1
November 11th, 2004, 03:27 PM
I think I am confused by creating a thread and begin a thread.
UINT threadFunc( LPVOID lp ) will be the definition of the thread. and
AfxBeginThread( threadFunc, (LPVOID)pParam ); will start this thread function. but where, and how is it created, is that UINT threadFunc( LPVOID lp ) will be the thread as well as the definition of the thread? if this is the case, there could be only one thread function, not two similiar thread function occures simousltanously?

chi_luci
November 11th, 2004, 03:36 PM
beginning a thread (AfxBeginThread(..) ) is like opening a program.. The same program can have multiple instances, right? So the threads can be based on the same function but the threads are total separated each from another.. You use their IDs to distinguish between them. (or the pointer to them ).
ex:


CWinThread* pThread1 = AfxBeginThread( threadFunc, NULL );
CWinThread* pThread2 = AfxBeginThread( threadFunc, NULL );
//when you need to send a message to this thread use
pThread1->PostThreadMessage( message1, wparam1, lparam1 );
//or for the second thread:
pThread2->PostThreadMessage( message1, wparam1, lparam1 );
//simple as that!

//killing thread1:
pThread1->PostThreadMessage( WM_CLOSE, 0, 0 );
//killing thread2:
pThread2->PostThreadMessage( WM_CLOSE, 0, 0 );

young1
November 11th, 2004, 04:02 PM
Thanks a lot, you make it as simple as it could be. however I still has some questions here is, everytime you use AfxBeginThread( threadFunc, NULL );
it will creat or call a threadFunc function right? then in oreder to ptrevent from producing many thread would it be like this

//first check if there is a thread, if there is a thread close it, after close it, call again to start a new thread.
if(pThread1!=NULL)
{ pThread1->PostThreadMessage( WM_CLOSE, 0, 0 );
CWinThread* pThread1 = AfxBeginThread( threadFunc, NULL );
}

else
//if there is not there, just start a new
pThread1->PostThreadMessage( WM_CLOSE, 0, 0 );

young1
November 11th, 2004, 04:25 PM
typo I mean

//first check if there is a thread, if there is a thread close it, after close it, call again to start a new thread.
if(pThread1!=NULL)
{ pThread1->PostThreadMessage( WM_CLOSE, 0, 0 );
CWinThread* pThread1 = AfxBeginThread( threadFunc, NULL );
}

else
//if there is not there, just start a new
CWinThread* pThread1 = AfxBeginThread( threadFunc, NULL );

Andreas Masur
November 11th, 2004, 05:21 PM
[ Moved thread ]

Andreas Masur
November 11th, 2004, 05:28 PM
Well...using the 'WM_CLOSE' message will only work if the thread does have a message queue which is only true for UI threads...

Take a look at the following FAQ (http://www.codeguru.com/forum/showthread.php?t=305166) for an example how to do it with worker threads which is the kind of thread you need here (at least as far as I understood the question)...

chi_luci
November 12th, 2004, 03:16 AM
I thought you want to create only 1 thread for processing..
I thread can process different messages, they are queued and handled 1 by one
for example:

#define TM_COPY_FILE WM_USER + 1
CWinThread* pThread = AfxBeginThread( threadFunc, NULL );

//......
//processing a message - for instance u need to copy a file
struct copyFile
{
CString szSource;
CString szDest;
};

void MessageHandler1()
{
copyFile* cf = new copyFile;
cf->szSource = _T( "c:\\file1.fff" );
cf->szDest = _T( "c:\\file2.fff" );
pThread->PostThreadMessage( TM_COPY_FILE, (WPARAM)cf, 0 );
}
void MessageHandler2()
{
copyFile* cf = new copyFile;
cf->szSource = _T( "c:\\file3.fff" );
cf->szDest = _T( "c:\\file4.fff" );
pThread->PostThreadMessage( TM_COPY_FILE, (WPARAM)cf, 0 );
}

UINT threadFunc( LPVOID lp )
{
DWORD dwThreadID = GetCurrentThreadId();//do something with this id.. use it to post messages to this thread
BOOL bRet = FALSE;
MSG msg ;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); // Force to make the queue
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
switch( msg.message )
{
case WM_CLOSE:
{
return -1;
}
break;
case TM_COPY_FILE:
{
copyFile* cf = (copyFile*)msg.lParam;
CopyFile( cf->szSource, cf->szDest, FALSE );
delete cf;
}
break;
}
return 1;
}

//you can do :
MessageHandler1();
MessageHandler2();
//with no problem.. requests will be qeued and solved one by one
//you don't have to close a thread then create it again ...
// the thread remains active until you explicitly close it (via TerminateThread or posting a close message; that happens because the thread has it's own message queue



What I mean is that you don't have to close the thread after processing a message. That's the model I'm using in all my multi-threaded applications and till now I never had any problems..
if you need a simple sample or some more explanations, please let me know.. :rolleyes:

young1
November 12th, 2004, 09:13 AM
please provide the sample, if you could, Thank you

chi_luci
November 12th, 2004, 11:41 AM
I've created a simple sample which illustrates the usage of threads for performing background operations..
the attachment is a project that copyes the files from a source directory into the destination directory, creating also the destination directory.. Important is to see that after you press the copy button, the files are copyed in background (are queued ) so that the main window does not "freeze". When copying is finished, a message is displayed.. Imagine, for instance that you wanna copy 1GB. If you are doing it inside the main thread, your dialog will "freeze" while copying.. Using a special thread it doesn't. :wave:

young1
November 12th, 2004, 01:24 PM
thanks a lot

young1
November 17th, 2004, 04:38 PM
chi_luci:
THe following is the program that I made accodring to the sample that you provioded. however I am facing several problem


CView.h

#define TM_MONITORING WM_USER+1
#define TM_DOWNLOADING WM_USER+2
#define TM_MESSAGE_FINISHED WM_USER+3

class CView: public CFormView
{
public:
CViewDoc* GetDocument() const;

// Operations
public:

// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual void OnInitialUpdate(); // called first time after construct

// Implementation
public:
virtual ~CView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
public:
CMscomm1 m_comm;
CEdit m_time;
int m_frequency;
float m_temperature;
float m_humidity;
CButton m_tilt;
CProgressCtrl m_progress;
afx_msg void OnRecording();
afx_msg void OnDownloading();
COleDateTime m_timec;
DECLARE_EVENTSINK_MAP()
void OnCommMscomm1();
enum {Recording, Monitoring,Downloading}m_status;
CEdit m_filename;
int datatotal;
DWORD m_thread; /*1.***************/

CString m_input1; /*2.***************/
CString m_input2; /*3.**************/

afx_msg void OnBnClickedButtonM();

static UINT threadFunc(LPVOID lp); /*4.*********/
private:



};

#ifndef _DEBUG //
inline CViewDoc* CView::GetDocument() const
{ return reinterpret_cast<CViewDoc*>(m_pDocument); }
#endif



CView.cpp
//part of cpp file

void CView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
//set downloading progress rang and position
m_progress.SetRange(0,255);
m_progress.SetPos(0);

datatotal=0;
m_status=Monitoring;

AfxBeginThread(threadFunc,this); //*5.****************//

}


void CView::OnCommMscomm1()
{
// TODO: Add your message handler code here

if(m_comm.get_CommEvent()==2)
{
VARIANT in_dat1;
short inputlen;

// in_dat=m_comm.GetInput();
unsigned char in_datanum=0;
inputlen=m_comm.get_InputLen();
in_dat1=m_comm.get_Input();
CString strInput(in_dat1.bstrVal);

if(strInput!='t')
m_input1=m_input1+strInput;
else
{ m_input2=m_input1; /*6.*********/
m_input1=""; /*7.*********/
switch(m_status)
{
case Monitoring:
PostThreadMessage /*8.******(m_thread,TM_MONITORING,0,0);
break;
case Downloading:
PostThreadMessage(m_thread,TM_DOWNLOADING,0,0);
break;
}
}
}
}

UINT CView::threadFunc(LPVOID lp)
{
CString part;
int value, partLength,valueth=1;
CView* pParent = (CView*)lp;
pParent->m_thread= GetCurrentThreadId();//saving the id
BOOL bRet = FALSE;
MSG msg ;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
switch( msg.message )
{
case WM_CLOSE:
{ return -1; }
break;

case TM_MONITORING:
{
CString a=pParent->m_input2; /*8.*****/
while(pParent->m_input2.GetLength()>0)
pParent->UpdateData(FALSE); /*9.******/
break;

case TM_DOWNLOADING:
{
pParent->UpdateData(FALSE); /*9.******/
}
break;


}//switch
}//while
return 1;
} //end





in Cview I defined CString m_input1, and CSting m_input2 and DWORD m_thread and threadFunc function (see /*1.****-/*4.*****)

I initiated threadFunc in OnInitialUpdate() (see /*5.*****)

I defined threadFunc also

I start call threadFunc by post messgae (see /*8.******)

before posting this message, I debuged and find that m_input2={" 158 158 158 "}; and m_input1="";

however, when I debuge into threadFunc(),
I got m_input2 is empty. I did not know why, and When I go to

young1
November 17th, 2004, 04:41 PM
chi_luci:
THe following is the program that I made accodring to the sample that you provioded. however I am facing several problem


CView.h

#define TM_MONITORING WM_USER+1
#define TM_DOWNLOADING WM_USER+2
#define TM_MESSAGE_FINISHED WM_USER+3

class CView: public CFormView
{
public:
CViewDoc* GetDocument() const;

// Operations
public:

// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual void OnInitialUpdate(); // called first time after construct

// Implementation
public:
virtual ~CView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
public:
CMscomm1 m_comm;
CEdit m_time;
int m_frequency;
float m_temperature;
float m_humidity;
CButton m_tilt;
CProgressCtrl m_progress;
afx_msg void OnRecording();
afx_msg void OnDownloading();
COleDateTime m_timec;
DECLARE_EVENTSINK_MAP()
void OnCommMscomm1();
enum {Recording, Monitoring,Downloading}m_status;
CEdit m_filename;
int datatotal;
DWORD m_thread; /*1.***************/

CString m_input1; /*2.***************/
CString m_input2; /*3.**************/

afx_msg void OnBnClickedButtonM();

static UINT threadFunc(LPVOID lp); /*4.*********/
private:



};

#ifndef _DEBUG //
inline CViewDoc* CView::GetDocument() const
{ return reinterpret_cast<CViewDoc*>(m_pDocument); }
#endif



CView.cpp
//part of cpp file

void CView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
//set downloading progress rang and position
m_progress.SetRange(0,255);
m_progress.SetPos(0);

datatotal=0;
m_status=Monitoring;

AfxBeginThread(threadFunc,this); //*5.****************//

}


void CView::OnCommMscomm1()
{
// TODO: Add your message handler code here

if(m_comm.get_CommEvent()==2)
{
VARIANT in_dat1;
short inputlen;

// in_dat=m_comm.GetInput();
unsigned char in_datanum=0;
inputlen=m_comm.get_InputLen();
in_dat1=m_comm.get_Input();
CString strInput(in_dat1.bstrVal);

if(strInput!='t')
m_input1=m_input1+strInput;
else
{ m_input2=m_input1; /*6.*********/
m_input1=""; /*7.*********/
switch(m_status)
{
case Monitoring:
PostThreadMessage /*8.******(m_thread,TM_MONITORING,0,0);
break;
case Downloading:
PostThreadMessage(m_thread,TM_DOWNLOADING,0,0);
break;
}
}
}
}

UINT CView::threadFunc(LPVOID lp)
{
CString part;
int value, partLength,valueth=1;
CView* pParent = (CView*)lp;
pParent->m_thread= GetCurrentThreadId();//saving the id
BOOL bRet = FALSE;
MSG msg ;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
switch( msg.message )
{
case WM_CLOSE:
{ return -1; }
break;

case TM_MONITORING:
{
CString a=pParent->m_input2; /*8.*****/
while(pParent->m_input2.GetLength()>0)
pParent->UpdateData(FALSE); /*9.******/
break;

case TM_DOWNLOADING:
{
pParent->UpdateData(FALSE); /*9.******/
}
break;


}//switch
}//while
return 1;
} //end





in Cview I defined CString m_input1, and CSting m_input2 and DWORD m_thread and threadFunc function (see /*1.****-/*4.*****)

I initiated threadFunc in OnInitialUpdate() (see /*5.*****)

I defined threadFunc also

I start call threadFunc by post messgae (see /*8.******)

before posting this message, I debuged and find that m_input2={" 158 158 158 "}; and m_input1="";

however, when I debuge into threadFunc(),
I got m_input2 is empty. I did not know why, and When I go to pParent->UpdateData(False); I also got an error message, a debuge asseration error msg occured. indicating file wincor.cpp line 888.

would you please help me solve the problem

chi_luci
November 18th, 2004, 05:29 PM
if you could put the project zipped up would be more easy. I don't know what exacly says the error (you could post the exact error and the last lines where it appears ).

anyway, hope I found the line which is very clear:

ASSERT((CWnd*)p == this); // must be us
// 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.


About that assertion, do not use UpdateData in another thread.
and the CString value - it should not happen. I've created a simple project to test that and it's ok. Probably the value is changing in the window thread before you process the message. you can use some syncronisation between the 2 threads to assure exclusive access.
I don't know exactly what you're trying to do, so can't help you much..