Archived

This topic is now archived and is closed to further replies.

Multi Threads... just a simple example plz...

This topic is 5574 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve looked around and found quite a lot on threads but they are so intertwined with other garbage I cant make heads or tails of it... I tried looking on MSDN but had to give up before I died of dehydration. (Should pin a note on my monitor stating I need supplies before venturing into the labyrinth that is MSDN) So if some one could kindly explain how a thread is formed I would be grateful. Thank you. btw its for a MFC dialog app... if that changes anything... but I purely want to know how to assign a class object to its own thread. thanks. crakinshot

Share this post


Link to post
Share on other sites
Just use _beginthreadex() to create the thread, and _endthreadex() to stop it.

MSDN says not to use CreateThread() when you are using the C run times because it creates memory leaks...... And even if you are not, just to be safe, stick to _beginthreadex(), its used the exact same way as CreateThread().

Its not so complicated, you just need to fill in a couple options, pass a function pointer, the thread starts.. And to end it you call _endthreadex() from within the thread... They have some code samples on MSDN.

Share this post


Link to post
Share on other sites
If you''re using MFC, you''ll either want to use ClassWizard to create your own CWinThread-derived class, or use AfxBeginThread. If you''re not using MFC, do as Max_Payne said.

CWinThread-derived class Create a CWinThread-derived class in ClassWizard. Your thread goes in the Run function of your new class. To run the thread:


CMyWinThread* p = new CMyWinThread;
p->m_bAutoDelete = true; // not sure if this is set automatically to true
p->CreateThread();


AfxBeginThread

UINT MyThread(LPVOID param)
{
// do stuff
return 0;
}

LPVOID param = 0;
AfxBeginThread(MyThread, param);

Share this post


Link to post
Share on other sites
quote:
Original post by Max_Payne
And to end it you call _endthreadex() from within the thread...
You can just return from the thread function to end the thread.

Ending a thread from another thread is potentially unsafe, as you might kill it while it''s doing stuff, and thus prevent it from releasing stuff it''s using.

Share this post


Link to post
Share on other sites
To help you along with _beginthreadex, here''s a header that wraps the call up as if it was CreateThread - and like mutex said, you don''t need to call endthreadex, just let the thread run out. endthreadex is there for "emergency" use.


  
/* createthreadex.h */
#ifndef CREATETHREADEX_H_
#define CREATETHREADEX_H_
#pragma once
#include <process.h>

/* ---------------------------------------------------------------------------
Q132078: "How to Use _beginthreadex() and _endthreadex()"
http://support.microsoft.com/default.aspx?scid=KB;EN-US;q132078&

When developing a multithreaded Win32-based application with Visual C++,
you need to use the CRT thread functions to create any threads that call
CRT functions. To create and terminate threads, use either _beginthread()
and _endthread() or _beginthreadex() and _endthreadex().

If you use the Win32 APIs CreateThread() and ExitThread() instead,
some of the CRT functions used in the thread will not work.
You need to use the CRT functions to both create and end the threads
or you lose the memory that the CRT allocates for the thread.

In addition to preventing memory leaks, using _beginthreadex places
a structured exception handling frame around the thread function
so that the signal function and floating point exceptions work correctly.

See also:

Win32 Q&A, MSJ July 1999
http://www.microsoft.com/msj/0799/win32/win320799.htm

Win32 Q&A, MSJ October 1999
http://www.microsoft.com/msj/1099/win32/win321099.htm

Here are two macro overlays to facilatate this usage:

Note:

The thread that uses CreateThreadEx to launch new threads should
also dispose of any generated thread handle using CloseHandle.

HANDLE MyThread = CreateThreadEx(...);
...
CloseHandle(MyThread);

--------------------------------------------------------------------------- */
typedef unsigned (__stdcall *StartAddressT)(void*);

#define CreateThreadEx( \
lpThreadAttributes, \
dwStackSize, \
lpStartAddress, \
lpParameter, \
dwCreationFlags, \
lpThreadId \
) \
( (HANDLE) _beginthreadex( \
(void *) (lpThreadAttributes), \
(unsigned int) (dwStackSize), \
(StartAddressT) (lpStartAddress), \
(void *) (lpParameter), \
(unsigned int) (dwCreationFlags), \
(unsigned int *) (lpThreadId) ) )


#define ExitThreadEx(dwExitCode) _endthreadex((unsigned int)dwExitCode)

#endif /* CREATETHREADEX_H_ */




Share this post


Link to post
Share on other sites
thanks guys for the help...

its ovois I''ll have to alter the structer of my code to incorperate this... which is annoying cus its working like a charm (except for the freezing... hehe)

anyway thanks;

ps. is there any danger of using the same objects in memory in two different threads? I know deleting objects would be futile with two threads running... but is there a problem with just accessing data?

and also... if say... you have your thread running.

and you want to return a class object back to the calling item. would this have to be done before I close the thread (or just returning 0); or after? my main concern is if I create an object while in a thread then close the thread the data is deleted along with the thread??...

Share this post


Link to post
Share on other sites
quote:
ps. is there any danger of using the same objects in memory in two different threads? I know deleting objects would be futile with two threads running... but is there a problem with just accessing data?


If no threads can change the data in any way, you do not need to synchronize access to the data.

If even one thread can modify the data in any way, you do need to synchronize accesso to the data.

To synchronize a thread, you create a CRITICAL_SECTION object that can be shared between all threads. When a thread is about to access the data, it must call EnterCriticalSection first, and then it must call LeaveCriticalSection after it has finished with the data. The CRITICAL_SECTION object ensures that only one thread gets access to the data at a time, and that each thread''s accesses are performed atomically (that is, all-at-once without interruption by other threads).

I think that MFC has a class that wraps up this CRITICAL_SECTION stuff for you.

Share this post


Link to post
Share on other sites
quote:
and you want to return a class object back to the calling item. would this have to be done before I close the thread (or just returning 0); or after? my main concern is if I create an object while in a thread then close the thread the data is deleted along with the thread??...


No, all threads share the process''s memory space, so they also share the process''s free store. You can freely create an object in one thread and delete it in another.

Share this post


Link to post
Share on other sites
quote:
Original post by null_pointer
I think that MFC has a class that wraps up this CRITICAL_SECTION stuff for you.
Indeed it does:

CCriticalSection g_cs;

CString g_sData; // data that requires synchronization

UINT ThreadOne(LPVOID param)
{
g_cs.Lock();
sData = "Blah";
g_cs.Unlock();
return 0;
}

UINT ThreadTwo(LPVOID param)
{
g_cs.Lock();
sData = "Asdf";
g_cs.Unlock();
return 0;
}


Thread synchronization is absolutely crucial. Any data modification or access needs to be synchronized. If not, your program will leak memory, crash, and do bad things to furry hamsters.

If it''s hard to imagine why such things would happen, just remember that two threads have the potential to execute simultaneously; the functions may run at the exact same time. What this means is that each line of code may be running simultaneously, not just entire blocks. Now try imagining your algorithm running twice at the same time to see if there are any problems.

P.S. It isn''t really truly simultaneous execution unless you have an SMP system, but I''ll leave that for someone else to explain

Share this post


Link to post
Share on other sites
quote:
Original post by mutex

CCriticalSection g_cs;
CString g_sData; // data that requires synchronization
UINT ThreadOne(LPVOID param)
{
g_cs.Lock();
sData = "Blah";
g_cs.Unlock();
return 0;
}



If unluckily sData got sick and throws an exception, your g_cs won''t be unlocked... and you will have some ''deadlock'', resulting ThreadTwo waiting......

Share this post


Link to post
Share on other sites
quote:
If unluckily sData got sick and throws an exception, your g_cs won't be unlocked... and you will have some 'deadlock', resulting ThreadTwo waiting......


Good point!

The typical solution is to write a guard class that will automatically lock and unlock the critical section for you.


    
class CGuard
{
CCriticalSection& cs;

public:
CGuard (CCriticalSection& cs) : cs (cs) { cs. Lock (); }
~CGuard (CCriticalSection& cs) { cs.Unlock (); }
};

CCriticalSection g_cs;
CString g_sData; // data that requires synchronization


UINT ThreadOne(LPVOID param)
{
CGuard MyGuard (g_cs);
sData = "Blah";
return 0;
}



Remember that CGuard will synchronize access to your whole function, which is probably not ideal. Normally, you should only synchronize access to the data and spend as little time within the synchronized section. After all you wish these threads to run asynchronously, right?

Here's how:



  
UINT ThreadOne(LPVOID param)
{
// <insert code to do other stuff>


{
CGuard MyGuard (g_cs); // <- it is locked here

sData = "Blah";
} // <- it is unlocked here


// <insert code to do other stuff>


return 0;
}


Although I thought that it was not a good idea to throw into system code (e.g., out of a thread function, out of a window function, etc.). If you use exceptions, you should do this to catch any exceptions that might be thrown out of the thread function:


  
UINT ThreadOne(LPVOID param)
{
try
{
// <insert code to do other stuff>


{
CGuard MyGuard (g_cs);
sData = "Blah";
}

// <insert code to do other stuff>

}

catch (...)
{
// <insert code to handle exception>

}

return 0;
}



[edited by - null_pointer on September 11, 2002 9:35:08 AM]

Share this post


Link to post
Share on other sites