by Alex Zhang
I am working on distributed calculation for complex security’s pricing , which multi-threads knowledge is crucial, so I write down some tips , notes , ticks here, it’s not academicals just a tracing for my process.
February 20th ,2009
1. Create Thread using Windows APIs
Syntax:
1: HANDLE CreateThread( 2: LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes 3: DWORD dwStackSize, // initial thread stack size 4: LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function 5: LPVOID lpParameter, // argument for new thread 6: DWORD dwCreationFlags, // creation flags 7: LPDWORD lpThreadId // pointer to receive thread ID 8: ); 9: Parameters: (From MSDN) lpThreadAttributes[in, optional]A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
The lpSecurityDescriptor member of the structure specifies a security descriptor for the new thread. If lpThreadAttributes is NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the primary token of the creator.
Windows XP/2000: The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the creator. This behavior changed with Windows XP with SP2 and Windows Server 2003. For more information, see Remarks.
dwStackSize [in]The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is zero, the new thread uses the default size for the executable. For more information, see Thread Stack Size.
lpStartAddress [in]A pointer to the application-defined function to be executed by the thread. This pointer represents the starting address of the thread. For more information on the thread function, see ThreadProc.
lpParameter [in, optional]A pointer to a variable to be passed to the thread.
dwCreationFlags [in]The flags that control the creation of the thread.
Value
Meaning
0
The thread runs immediately after creation.
CREATE_SUSPENDED 0×00000004
The thread is created in a suspended state, and does not run until the ResumeThread function is called.
STACK_SIZE_PARAM_IS_A_RESERVATION 0×00010000
The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the commit size.
Windows 2000: The STACK_SIZE_PARAM_IS_A_RESERVATION flag is not supported.
lpThreadId [out, optional]A pointer to a variable that receives the thread identifier. If this parameter is NULL, the thread identifier is not returned.
Return Value
If the function succeeds, the return value is a handle to the new thread.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
Note that CreateThread may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread’s process. This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).
Specially Show the “ThreadProc” Function Here:
DWORD WINAPI ThreadProc(LPVOID lpParameter); replacing ThreadProc with the name of the function.
2. Manage Thread
2.1 Resume Thread (From MSDN)
Decrements a thread’s suspend count. When the suspend count is decremented to zero, the execution of the thread is resumed.
A handle to the thread to be restarted.
This handle must have the THREAD_SUSPEND_RESUME access right. For more information, see Thread Security and Access Rights.
If the function succeeds, the return value is the thread’s previous suspend count.
If the function fails, the return value is (DWORD) -1. To get extended error information, call GetLastError.
2.3 Suspend Thread (From MSDN)
SuspendThread Function
Suspends the specified thread.
A 64-bit application can suspend a WOW64 thread using the Wow64SuspendThreadfunction.
A handle to the thread that is to be suspended.
The handle must have the THREAD_SUSPEND_RESUME access right. For more information, see Thread Security and Access Rights.
If the function succeeds, the return value is the thread’s previous suspend count; otherwise, it is (DWORD) -1. To get extended error information, use the GetLastErrorfunction.
2.4 Waiting for terminate (From MSDN)
Obviously if “ThreadProc” hasn’t returned within 0.1 seconds then something is wrong, but that isn’t the point. The WaitForSingleObject() function solves this problem.
WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE,DWORD);
WaitForSingleObject() waits until either the thread has terminated or the timeout value provided in the second parameter has elapsed. For this function we need the handle of the thread. MSDN recommends that all handles are closed with the CloseHandle() function before the program terminates.
2.5 Terminate Threads
A handle to the thread to be terminated.
The handle must have the THREAD_TERMINATE access right. For more information, seeThread Security and Access Rights.
dwExitCode [in]The exit code for the thread. Use the GetExitCodeThread function to retrieve a thread’s exit value.
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, callGetLastError.
AHA! A link http://msdn.microsoft.com/en-us/library/ms684847(VS.85).aspx is much more than copy and paste.
3.Utilities For Synchronization
As you know , Mutex, event , lock and semaphore are for this, what we need to do is OO it. Luckily , the laborious have done this:
For Example (From http://www.relisoft.com/Win32/active.html):
Mutex:
1: class Mutex 2: { 3: friend class Lock; //grant Lock object full control rights 4: public: 5: Mutex () { InitializeCriticalSection (& _critSection); } 6: ~Mutex () { DeleteCriticalSection (& _critSection); } 7: private: 8: void Acquire () 9: { 10: EnterCriticalSection (& _critSection); 11: } 12: void Release () 13: { 14: LeaveCriticalSection (& _critSection); 15: } 16: 17: CRITICAL_SECTION _critSection; 18: };Lock:
1: class Lock 2: { 3: public: 4: // Acquire the state of the semaphore 5: Lock ( Mutex & mutex ) 6: : _mutex(mutex) 7: { 8: _mutex.Acquire(); 9: } 10: // Release the state of the semaphore 11: ~Lock () 12: { 13: _mutex.Release(); 14: } 15: private: 16: Mutex & _mutex; 17: };Event:
1: class Event 2: { 3: public: 4: Event () 5: { 6: // start in non-signaled state (red light) 7: // auto reset after every Wait 8: _handle = CreateEvent (0, FALSE, FALSE, 0); 9: } 10: ~Event () 11: { 12: CloseHandle (_handle); 13: } 14: // put into signaled state 15: void Release () { SetEvent (_handle); } 16: void Wait () 17: { 18: // Wait until event is in signaled (green) state 19: WaitForSingleObject (_handle, INFINITE); 20: } 21: operator HANDLE () { return _handle; } 22: private: 23: HANDLE _handle; 24: };Semaphore VS Mutex:
http://ju-kevin.spaces.live.com/blog/cns!907BD90CD611C0C7!221.entry?wa=wsignin1.0&sa=531454868
Thread:
#define DCalc_Log //
#define QL_REQUIRE //
class Thread { public: Thread ( unsigned ( __stdcall * pFun) (void* arg), void* pArg) { _handle = (HANDLE)CreateThread ( 0, // Security attributes 0, // Stack size pFun, pArg, CREATE_SUSPENDED, &_tid); QL_REQUIRE(_handle!=0,"Creat Thread Failure"); DCalc_Log("Creat Thread OK , tid=%d",_tid); } virtual ~Thread () { DCalc_Log("Thread Release"); HRESULT hRes(S_OK); GetExitCodeThread(_handle, (LPDWORD) &hRes); CloseHandle (_handle); DCalc_Log("Thread %d exit code = %un",_tid, hRes); } void Resume () { ResumeThread (_handle); } void WaitForDeath () { WaitForSingleObject (_handle, INFINITE); } private: HANDLE _handle; unsigned _tid; };4. Com Multi-Thread Model
As of the application environment (COM DLL), some knowledge about COM multi-thread model is important.
see FW:COM Multi-Thread Model
5. My Application
Base Class:
1: class DCalcThread 2: { 3: public: 4: DCalcThread () 5: : _thread (ThreadEntry, this) 6: { 7: } 8: 9: virtual void RunDCalc () = 0; 10: virtual ~DCalcThread () {} 11: 12: protected: 13: struct COMEnvSetting 14: { 15: COMEnvSetting() 16: { 17: // ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 18: } 19: ~COMEnvSetting() 20: { 21: // ::CoUninitialize(); 22: } 23: }; 24: static unsigned __stdcall ThreadEntry (void *pArg) 25: { 26: // COMEnvSetting _envSetter; 27: DCalcThread * pActive = (DCalcThread *) pArg; 28: pActive->RunDCalc(); 29: 30: return 0; 31: }; 32: 33: int _isDying; 34: Thread _thread; 35: };Sub Classes:
Sample subclass A:
1: #define DCalc_Log // 2: class DCalcCNPV: public DCalcThread 3: { 4: public: 5: DCalcCNPV(); 6: ~DCalcCNPV(); 7: 8: void RunDCalc () 9: { 10: DCalc_Log("Calc NPV"); 11: } 12: private: 13: }; Sample subclass B: 1: #define DCalc_Log // 2: class DCalcCNPV: public DCalcThread 3: { 4: public: 5: DCalcCNPV(); 6: ~DCalcCNPV(); 7: 8: void RunDCalc () 9: { 10: DCalc_Log("Calc NPV"); 11: } 12: private: 13: };I type some links here , making up for the lost of my re-product:
http://www.relisoft.com/Win32/active.html
http://www.geocities.com/samuel_super_camel/MultiThreadingTutorial.htm
http://www.cs.rpi.edu/academics/courses/netprog/WindowsThreads.html