Synchronization of threads in Windows

Source: Internet
Author: User

 

Although multithreading can bring us benefits, there are also many problems to solve. For example, for a dedicated system resource such as a disk drive, because the thread can execute any code segment of the process and the thread runs automatically by the System Scheduling, there is a certain degree of uncertainty, therefore, two threads may simultaneously operate on the disk drive, resulting in an operation error. For example, a computer in the banking system may use one thread to update its user database, another thread is used to read the database to respond to the needs of the depositor. It is very likely that the thread reading the database reads the database that is not completely updated, this may be because only a portion of the data has been updated during reading.

It is called the synchronization of threads to make the threads of the same process work in a coordinated and consistent manner. MFC provides a variety of synchronization objects. The following describes only the four most commonly used objects:

  • Ccriticalsection)
  • Event (cevent)
  • Mutex (cmutex)
  • Semaphores (csemaphore)
     

Through these classes, we can easily achieve thread synchronization.

A. Use the ccriticalsection class

When multiple threads access a dedicated shared resource, you can use the "critical section" object. At any time, only one thread can have an object in the critical section. threads in the critical section can access protected resources or code segments. Other threads wishing to enter the critical section will be suspended and waiting, this ensures that multiple threads do not access Shared resources at the same time.

The procedure for using the ccriticalsection class is as follows:
 

  1. Defines a Global Object of the ccriticalsection class (to make each thread accessible), such as the ccriticalsection critical_section;
  2. Call the member lock () of the ccriticalsection class to obtain the critical zone object before accessing the resources or code to be protected:
    critical_section.Lock();

    This function is called in the thread to obtain the critical section requested by the thread. If no other thread occupies the critical zone object at this time, the thread that calls lock () gets the critical zone; otherwise, the thread will be suspended and put into a system queue for waiting, until the thread with a critical section has been released.

  3. After the access to the critical section is complete, use the member function unlock () of the ccriticalsection to release the critical section:
    critical_section.Unlock();

    In other words, thread a executes the critical_section.lock () statement, if other threads (B) are executing the critical_section.lock (); Statement and critical_section. unlock (); the statement before the statement, thread a will wait until thread B finishes executing critical_section. unlock (); statement, thread a will continue to execute.

The following is an example.

Routine 8 multithread8

  1. Create a project multithread8 Based on the dialog box. In the idd_multithread8_dialog dialog box, add two buttons and two edit box controls. The IDS of the two buttons are idc_writew and idc_writed, respectively, the title is "Write 'W'" and "Write 'D'" respectively. The IDS of the two edit boxes are idc_w and idc_d, And the read-only attribute is selected;
  2. Declare two thread functions in the multithread8dlg. h file:
    UINT WriteW(LPVOID pParam);UINT WriteD(LPVOID pParam);
  3. Use classwizard to add the cedit class variables m_ctrlw and m_ctrld to idc_w and idc_d respectively;
  4. Add the following content to the multithread8dlg. cpp file:

    To correctly use the synchronization class in a file, add the following content at the beginning of the file:

    #include "afxmt.h"

    Defines the critical section and a character array. To be used between different threads, it is defined as a global variable:

    CCriticalSection critical_section;char g_Array[10];

    Add a thread function:

    Uint writew (lpvoid pparam) {cedit * pedit = (cedit *) pparam; pedit-> setwindowtext (""); critical_section.lock (); // lock the critical section, when other threads encounter critical_section.lock (); when the statement is executed, wait // until the critical_section.unlock (); statement for (INT I = 0; I <10; I ++) {g_array [I] = ''w''; pedit-> setwindowtext (g_array); sleep (1000);} critical_section.unlock (); Return 0;} uint writed (lpvoid pparam) {cedit * pedit = (cedit *) pparam; pedit-> setwindowtext (""); critical_section.lock (); // lock the critical section. Other threads encounter critical_section.lock (); wait // until the critical_section.unlock (); statement for (INT I = 0; I <10; I ++) {g_array [I] = ''d ''; pedit-> setwindowtext (g_array); sleep (1000);} critical_section.unlock (); Return 0 ;}
  5. Double-click idc_writew and idc_writed to add the response function:
    void CMultiThread8Dlg::OnWritew() {CWinThread *pWriteW=AfxBeginThread(WriteW,&m_ctrlW,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteW->ResumeThread();}void CMultiThread8Dlg::OnWrited() {CWinThread *pWriteD=AfxBeginThread(WriteD,&m_ctrlD,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteD->ResumeThread();}

    Because the code is relatively simple, it is not detailed in detail. Compile and run the routine. You can click two buttons to observe the function of the critical class.

B. Use the cevent class

The cevent class provides event support. An event is a synchronization object that allows a thread to wake up in a certain situation. For example, in some network applications, one thread (as a) is responsible for listening to the communication port, and the other thread (as B) is responsible for updating user data. By using the cevent class, thread a can notify thread B when to update user data. Each cevent object can have two states: Signal State and no signal state. The thread monitors the status of the cevent Class Object in it, and takes corresponding actions accordingly.
In MFC, there are two types of cevent objects: manual events and automatic events. An automatic cevent object is automatically returned to the non-signal state after at least one thread is released. However, after the human event object obtains the signal, it releases the available thread until it calls the member function resetevent () set it to the stateless state. When you create a cevent Class Object, automatic events are created by default. The prototype and parameters of the member functions of the cevent class are described as follows:

1、CEvent(BOOL bInitiallyOwn=FALSE,          BOOL bManualReset=FALSE,          LPCTSTR lpszName=NULL,          LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);

 

  • Binitiallyown: Specifies the initialization status of the event object. True indicates a signal, and false indicates no signal;
  • Bmanualreset: Specifies whether the event to be created is a manual event or an automatic event. True indicates a manual event, and false indicates an automatic event;
  • The last two parameters are generally set to null, which is not described here.
2、BOOL CEvent::SetEvent();

Set the status of the cevent class object to a signal state. If the event is a manual event, the cevent class object remains in a signal State until the member function resetevent () is called to reset it to a non-signal state. If the cevent class object is an automatic event, after setevent () sets the event to a signal state, the cevent class object is automatically reset from the system to a non-signal state.

If the function is successfully executed, a non-zero value is returned. Otherwise, zero is returned.

3、BOOL CEvent::ResetEvent();

This function sets the event status to stateless, and maintains the status until setevent () is called. Because automatic events are automatically reset by the system, automatic events do not need to call this function. If the function is successfully executed, a non-zero value is returned. Otherwise, zero is returned. We generally call the waitforsingleobject function to monitor the event status. We have already introduced this function. Because of the language description, the understanding of the cevent class is indeed difficult, but you only need to carefully taste the following routine and read it several times.

Routine 9 multithread9

  1. Create a project multithread9 Based on the dialog box. In the idd_multithread9_dialog dialog box, add a button and two edit box controls. The ID of the button is idc_writew and the title is "Write 'W '"; the IDS of the two edit boxes are idc_w and idc_d, And the read-only attribute is selected;
  2. Declare two thread functions in the multithread9dlg. h file:
    UINT WriteW(LPVOID pParam);UINT WriteD(LPVOID pParam);
  3. Use classwizard to add the cedit class variables m_ctrlw and m_ctrld to idc_w and idc_d respectively;
  4. Add the following content to the multithread9dlg. cpp file:

    To correctly use synchronization classes in files, add

    #include "afxmt.h"

    Defines the event object and a character array. To be used between different threads, it is defined as a global variable.

    CEvent eventWriteD;char g_Array[10];

    Add a thread function:

    UINT WriteW(LPVOID pParam){CEdit *pEdit=(CEdit*)pParam;pEdit->SetWindowText("");for(int i=0;i<10;i++){g_Array[i]=''W'';    pEdit->SetWindowText(g_Array);Sleep(1000);}eventWriteD.SetEvent();return 0;}UINT WriteD(LPVOID pParam){CEdit *pEdit=(CEdit*)pParam;pEdit->SetWindowText("");WaitForSingleObject(eventWriteD.m_hObject,INFINITE);for(int i=0;i<10;i++){g_Array[i]=''D'';    pEdit->SetWindowText(g_Array);Sleep(1000);}return 0;}

    By carefully analyzing these two thread functions, you will understand the cevent class correctly. The thread writed executes to waitforsingleobject (eventwrited. m_hobject, infinite); wait until the event eventwrited is a signal and the thread is executed. Because the eventwrited object is an automatic event, when waitforsingleobject () returns, the system automatically resets the eventwrited object to the stateless state.

  5. Double-click the idc_writew button to add the response function:
    void CMultiThread9Dlg::OnWritew() {CWinThread *pWriteW=AfxBeginThread(WriteW,&m_ctrlW,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteW->ResumeThread();CWinThread *pWriteD=AfxBeginThread(WriteD,&m_ctrlD,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteD->ResumeThread();}

    Compile and run the program, and click "Write 'W'" to understand the role of the event object.

C. Use cmutex class

The mutex object is similar to the object in the critical section. The difference between the mutex object and the object in the critical section is that the mutex object can be used between processes, while the object in the critical section can only be used between threads of the same process. Of course, mutex objects can also be used between various threads of the same process, but in this case, using the critical section will save more system resources and improve efficiency.

D. Use the csemaphore class

When a counter is required to limit the number of threads that can be used, the "semaphore" object can be used. The csemaphore class object stores the Count value of the thread that currently accesses a specified resource. The Count value is the number of threads that can still use this resource. If the Count reaches zero, all access attempts to the resources controlled by the csemaphore class object will be put into a queue for waiting until the timeout or the Count value is not zero. When a thread is released and has accessed the protected resource, the Count value is reduced by 1. When a thread completes access to the controlled shared resource, the Count value increases by 1. The maximum number of threads that can be accessed by resources controlled by csemaphore objects at the same time is specified in the object's build function.

The constructor prototype and parameters of the csemaphore class are described as follows:

CSemaphore (LONG lInitialCount=1,            LONG lMaxCount=1,            LPCTSTR pstrName=NULL,            LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);
  • Linitialcount: the initial count value of the semaphore object to access the initial value of the number of threads;
  • Lmaxcount: Maximum number of threads that can access resources protected by semaphores at the same time;
  • The latter two parameters are generally null in the same process and are not discussed too much;

When using the csemaphore constructor to create a semaphore object, you must specify the maximum allowed resource count and the current available resource count. Generally, the current available resource count is set to the maximum Resource Count. Each time a thread is added to access a shared resource, the current available resource count is reduced by 1, as long as the current available resource count is greater than 0, a semaphore signal can be sent. However, when the current available count is reduced to 0, it indicates that the number of threads currently occupying resources has reached the maximum allowed number, and other threads cannot enter, at this time, the semaphore signal cannot be sent. After processing shared resources, the thread should use the releasesemaphore () function to add 1 to the number of currently available resources while leaving.

The following is a simple example to illustrate the csemaphore class usage.

Routine 10 multithread10

  1. Create a project multithread10 Based on the dialog box. In the idd_multithread10_dialog dialog box, add a button and three edit box controls. The button ID is idc_start, the title is "Write 'A', 'B', and 'C' at the same time". The IDS of the three edit boxes are idc_a, idc_ B, and idc_c, respectively, and the attributes are read-only;
  2. Declare two thread functions in the multithread10dlg. h file:
    UINT WriteA(LPVOID pParam);UINT WriteB(LPVOID pParam);UINT WriteC(LPVOID pParam); 
  3. Use classwizard to add cedit variables m_ctrla, m_ctrlb, and m_ctrlc to idc_a, idc_ B, and idc_c respectively;
  4. Add the following content to the multithread10dlg. cpp file:

    To correctly use the synchronization class in a file, add the following content at the beginning of the file:

    #include "afxmt.h"

    Defines a semaphore object and a character array. To be used between different threads, it is defined as a global variable:

    Csemaphore semaphorewrite (); // The maximum number of threads for resource access is 2. Currently, the number of accessible threads is 2 char g_array [10];

    Add three thread functions:

    UINT WriteA(LPVOID pParam){CEdit *pEdit=(CEdit*)pParam;pEdit->SetWindowText("");WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);CString str;for(int i=0;i<10;i++){        pEdit->GetWindowText(str);g_Array[i]=''A'';str=str+g_Array[i];    pEdit->SetWindowText(str);Sleep(1000);}ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);return 0;}UINT WriteB(LPVOID pParam){CEdit *pEdit=(CEdit*)pParam;pEdit->SetWindowText("");WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);CString str;for(int i=0;i<10;i++){        pEdit->GetWindowText(str);g_Array[i]=''B'';str=str+g_Array[i];    pEdit->SetWindowText(str);Sleep(1000);}ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);return 0;}UINT WriteC(LPVOID pParam){CEdit *pEdit=(CEdit*)pParam;pEdit->SetWindowText("");WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);for(int i=0;i<10;i++){g_Array[i]=''C'';    pEdit->SetWindowText(g_Array);Sleep(1000);}ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);return 0;}

    These three thread functions are no longer mentioned. When the semaphores object has a signal, the thread executes the waitforsingleobject statement to continue the execution. At the same time, the number of available threads is reduced by 1. If the semaphores object has no signal when the thread executes the waitforsingleobject statement, the thread waits here until the semaphore object has a signal thread.

  5. Double-click the idc_start button to add the response function:
    void CMultiThread10Dlg::OnStart() {CWinThread *pWriteA=AfxBeginThread(WriteA,&m_ctrlA,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteA->ResumeThread();CWinThread *pWriteB=AfxBeginThread(WriteB,&m_ctrlB,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteB->ResumeThread();CWinThread *pWriteC=AfxBeginThread(WriteC,&m_ctrlC,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);pWriteC->ResumeThread();}
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.