This article illustrates a common mode in multi-threaded programming, which is mainly described below: 1. There are a kindergarten, there are several teachers and a lot of children, there is a maze to children to play 2. Teachers can arrange maze. 3. When a teacher is arranged in the maze, in order to be safe, the children can not be in the maze 4. You can't let more than one teacher also arrange the maze, so that you can mess with the maze. 5. When there is no teacher, when you have a maze, your child They can freely enter and out of the maze, playing inside 6. When a teacher wants to enter the maze, he must hang a brand, saying that the teacher should clean the maze, do not let the children come in (but the child already in the maze can continue to play When there is no child in the labyrinth, the teacher can organize the maze. After finishing, the teacher can take the brand.
Or you can say this:
1. There is a shared resource 2. One or more threads write this resource (the most common is a write thread, if you want to change to multiple threads, it is very simple, most of which just add a critical code segment) 3. Read more Threads and write threads remain mutually exclusive 4. Write threads To ensure mutual exclusive 5. Because of the efficiency, there is no need to keep mutually exclusive. 6. Because there are many read threads, write threads must take Sustainable measures to prevent yourself not get the opportunity to schedule
-------------------------------------------------- ---------------
There is an example on the MSDN. In this program, it is a write thread, multiple read threads, each thread has an EVENT object, using WaitFormultiPleObjects to keep mutually exclusive
1. This is a code segment that creates a thread: #define Numthreads 4
Handle HglobalWriteEvent;
Void CreateEventsandthreads (Void) {Handle Hreadevents [NUMTHREADS], HTHREAD; DWORD I, IDTHREAD;
// CREATE A Manual-reset Event Object. The master thread sets // this to nonsignaled when ipient to the shared buffer. // Prevent other threads from reading at Event
HglobalWriteEvent = CreateEvent (null, // no security attributes true, //manual-reset evenet turn, // initial state is signal name);
IF (hglobalwriteevent == null) {// error exit}
.
For (i = 1; i <= numthreads; i ) {// crete the auto-reset evenet. HReadevents [i] = createEvent (null, // no security attributes false, // auto-reset round true, // initial STATE IS SIGNALED NULL); // Object Not Namedif (Hreadevents [i] == NULL) {// error exit.
hthread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunction, & HreadEvents [i], // pass handle 0, & idthread; if (hthread == null) {// error exit.}}}}}}
2. This is the code segment that is written to the resource. From the context, it should be working in the main thread: void WriteTobuffer (void) {DWORD DWWAITRESULT, I;
// RESET HGLOBALWRITEEVENT To Nonsignaled, To Block Readers. // Block Read Thread IF (! Resevent (HglobalWriteEvent) {// error exit.
// Wait for All Reading Threads to finish recaps.
dwWaitResult = WaitForMultipleObjects (// wait for all threads to finish reading NUMTHREADS, // number of handles in array hReadEvents, // array of read-event handles TRUE, // wait until all are signaled INFINITE); // indefinite wait
Switch (dwaitResult) {// all read-event objects were signal-wait_Object_0: // Write to the shared buffer. break;
// An error Occurred. Default: Printf ("Wait Error:% D / N", getLastError ()); EXITPROCESS (0);
// set hglobalWriteEvent to signaled.
IF (! setEvent (hglobalwriteever)) {// error exit.
// SET All Read Events to Signaled. FOR (i = 1; I <= NUMTHREADS; i ) IF (! SetEvent (HREADEVENTS [I])) {// error exit.}} 3. This is the code reading thread : Void threadfunction (lpvoid lpparam) {dWord dwaitresult; handle hevents [2]; hevents [0] = * (handle *) LPPARAM; // thread's read emergevents [1] = hglobalwriteEvent;
DWWAITRESULT = WAITFORMULTIPLEOBJECTS (2, // Number of Handles in Array HEVENTS, // Array of Event Handles True, // Wait Till All Arei Signaled Infinite); // Indefinite Wait
Switch (dwaitresult) {
// Both Event Objects Were Signaled. Case Wait_Object_0: // Read from The Shared Buffer. Break;
// An error Occurred. Default: Printf ("Wait Error:% D / N", getLastError ()); exitthread (0);}
// set the read event to signaled.
IF (! setEvent (hevents [0])) {// error exit.}
-------------------------------------------------- ------------------------------
This example has achieved the requirements of the requirements, but also not bother, but we want to use a more simple method to implement a class, you can use g_swmrg.waittoread () like the following way, read ... g_swmrg.donRead () ;
g_swmrg.waittowrite (); writing ... g_swmrg.donRead ();
It is undoubtedly the easiest way to use the key code segment, but it does not apply to this article, as this is a mutually exclusive relationship between the reading thread, causing a decline in efficiency.
It seems that two mutually exclusive objects must be used. When the code tries to write resources, he must guarantee that there is no other thread to read and write when the code is trying to read, he must guarantee that there is no resource being written: we use two EVENT object: m_wlock, m_rlock (read lock), these two object initialization values are Signaled State, not using automatic mode M_Rlock = :: CreateEvent (null, true, true, null);
/ / -------------------------------------------------------------------------------------------- ---- 1 waits write void WaitToWrite () {:: EnterCriticalSection (& m_cs);. DWORD dwWaitResult = :: WaitForSingleObject (m_rlock, INFINITE); if (dwWaitResult == WAIT_OBJECT_0) :: ResetEvent (m_wlock); // not Read Else Printf ("Waitwrite Error! / N") ;: LeaveCritics;} 2. Write complete void endwrite () {:: setEvent (m_wlock); // Wake-up waiting reading thread} 3. Waiting to read void WaitToRead () {:: EnterCriticalSection (& m_cs); DWORD dwWaitResult = :: WaitForSingleObject (m_wlock, INFINITE); if (dwWaitResult == WAIT_OBJECT_0) {:: ResetEvent (m_rlock); InterlockedIncrement ((long *) & m_nReadNum); // M_nreadnum This means how many threads are reading} else printf ("WaitWrite Error! / N"); :: LeavecriticalSection;} 4. Read Complete Void endRead () {:: EntercriticalSECTION (& m_cs); if (0 > = = InterlockedDecrement ((long *) & m_nreadnum) // m_nreadnum--; :: setEvent (m_rlock); // When there is no thread read, // Wake-up Writes Write thread} This example is already working properly, but we I found a problem, when multiple threads read, because the write thread is to be written to the active reading thread, it can be written, it will be difficult to get the opportunity to call, and even starve to die, to solve this problem , We can set a thing before writing a thread waiting. (Teacher wants to hang a brand), when reading threads, I will wait, the modified code is as follows: ------------------------- -------------------------------------------------- -----
// srwm1.h: interface for the cshwm1 class.////
#if! defined (afX_srwm1_h__62a82971_1c04_4ec9_8a52_c0392e333575__included _) # define afx_srwm1_h__62a82971_1c04_4ec9_8a52_c0392e333575__included_
#if _msc_ver> 1000 # pragma overce # endif //_MSC_VER> 1000 # include
#include
Class CSRWM1 {Private: Handle M_Rlock; // Read Lock Handle M_Wlock [2]; // Write Critical_SECTION M_CS; // Key Segment Volatile Long M_NReadNum; Public: // ----------- ---------------------- CSRWM1 () {m_rlock = :: CreateEvent (null, true, true, null); m_wlock [0] = :: createEvent NULL, TRUE, TRUE, NULL; M_WLOCK [1] = :: CreateEvent (NULL, TRUE, TRUE, NULL); :: InitializeCriticalSection (& M_CS); if (m_rlock == null) PERROR ("M_Rlock Init Error! / N "); If (m_wlock [0] == null) PERROR (" m_wlock init error! / N "); if (m_wlock [1] == null) PERROR (" M_WLOCK INT Error! / N "); m_nreadnum = 0 Virtual ~ csrwm1 () {:: closehandle (m_rlock) ;:: CloseHandle (m_wlock [0]); :: closehandle (m_wlock1]); :: deletecriticalsection (& m_cs);} // ------- ------------------------------- void waittowrite () {:: EntercriticalSection (& M_CS); :: Resevent (m_wlock [1 ]); DWORD DWWAITRESULT = :: WaitForsingleObject (M_Rlock, Infinite); if (dwwaitresult == Wait_Object_0) :: Resevent (m_wlock " 0]); Else Printf ("Waitwrite Error! / N") ;: LeaveCritics;} void endwrite () {:: setwr (m_wlock [1]); :: setEvent (m_wlock [0]);} // --------------------------------------- void waittoread () {:: EntercriticalSection (& m_cs); DWORD dwWaitResult = :: WaitForMultipleObjects (2, m_wlock, TRUE, INFINITE); if (dwWaitResult == WAIT_OBJECT_0) {:: ResetEvent (m_rlock); InterlockedIncrement ((long *) & m_nReadNum);} else printf ( "WaitWrite Error! / N ") ;: LeavecriticalSection;} void endread () {if (0> = interlockedDecrement ((long *) &
M_nreadnum) :: setEvent (m_rlock);}}; # endif ///! defined (AFX_SRWM1_H__62A82971_1C04_4EC9_8A52_C0392E3333575__included_)