1. Critical section: access to a common resource or a piece of code through serialization of multiple threads, fast, suitable for controlling data access.
  2. Mutex: Designed to coordinate separate access to a shared resource together.
  3. Semaphores: Designed to control a resource with a limited number of users.
  4. Event: Used to notify threads that some event has occurred, thus initiating the start of subsequent tasks.
  5. Queue: Queue processing.

Critical Section

An easy way to ensure that only one thread can access data at a time. Only one thread is allowed to access a shared resource at any time. If multiple threads attempt to access a critical section at the same time, any thread attempting to access the critical section after one thread enters will be suspended until the thread entering the critical section leaves. After the critical section is released, other threads can continue to preempt and thus operate atomically on shared resources. Is to set up a stool, only let a person sit, if the previous one has not come down, the behind will have been waiting, that is, locked

A critical section contains two operation primitives:

- EnterCriticalSection () - LeaveCriticalSection ()Copy the code
  • Through multi-threaded serialization to access a common resource or a piece of code, fast, suitable for controlling data access.
  • EnterCriticalSection after the EnterCriticalSection () statement is executed the code will enter the critical section and then whatever happens, you must make sure that the matching LeaveCriticalSection () is executed. Otherwise the shared resources protected by the critical section will never be released. Although the synchronization speed of the critical section is very fast, it can only be used to synchronize threads within the process, not threads in multiple processes.
Code: //CriticalSection CCriticalSection global_CriticalSection; Char global_Array[256]; // Initialize the shared resource void InitializeArray() {for(int I = 0; i<256; i ) { global_Array[i]=I; }} UINT Global_ThreadWrite(LPVOID pParam) {CEdit * PTR =(CEdit *)pParam; ptr->SetWindowText(""); Global_criticalsection.lock (); global_criticalsection.lock (); for(int i = 0; i<256; i ) { global_Array[i]=W; ptr->SetWindowText(global_Array); Sleep(10); } global_criticalsection.unlock (); return 0; } UINT Global_ThreadDelete(LPVOID pParam) {CEdit * PTR =(CEdit *)pParam; ptr->SetWindowText(""); Global_criticalsection.lock (); global_criticalsection.lock (); for(int i = 0; i<256; i ) { global_Array[i]=D; ptr->SetWindowText(global_Array); Sleep(10); } global_criticalsection.unlock (); return 0; } / / create a Thread and Start the Thread void CCriticalSectionsDlg: : OnBnClickedButtonLock () {/ / Start the first Thread CWinThread * ptrWrite = AfxBeginThread(Global_ThreadWrite, &m_Write, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); PtrWrite - > ResumeThread (); //Start the second Thread CWinThread *ptrDelete = AfxBeginThread(Global_ThreadDelete, &m_Delete, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); ptrDelete->ResumeThread(); }Copy the code

Mutex

Mutex is similar to a critical section in that only the thread that owns the mutex has access to the resource. Since there is only one mutex, it is determined that the shared resource will never be accessed by multiple threads at the same time. The thread currently occupying the resource should surrender the mutex it owns after the task is completed so that other threads can access the resource once they have acquired it. Muexes are more complex than critical sections. Because using mutex can not only achieve safe sharing of resources between different threads of the same application, but also between different threads of the application.

Set up a row of closets where everyone can get the key, but if the closet is in use, you have to wait. People with the same key are mutually exclusive, and keys are mutually exclusive.

Mutex contains several operation primitives:

CreateMutex () creates a mutex OpenMutex () opens a mutex ReleaseMutex () releases the mutex WaitForMultipleObjects () waits for the mutex objectCopy the code
MFC also provides a CMutex class for mutex. Using the CMutex class to implement mutex operations is simple, CMutex(BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL) Do not fill in unused parameters, which may result in unexpected results. CMutex global_Mutex(0,0,0); Char global_Array[256]; void InitializeArray() { for(int i = 0; i<256; i ) { global_Array[i]=I; } } UINT Global_ThreadWrite(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); global_Mutex.Lock(); for(int i = 0; i<256; i ) { global_Array[i]=W; ptr->SetWindowText(global_Array); Sleep(10); } global_Mutex.Unlock(); return 0; } UINT Global_ThreadDelete(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); global_Mutex.Lock(); for(int i = 0; i<256; i ) { global_Array[i]=D; ptr->SetWindowText(global_Array); Sleep(10); } global_Mutex.Unlock(); return 0; }Copy the code

Semaphores

Unlike the previous methods, semaphore objects synchronize threads. Signals allow multiple threads to use a shared resource at the same time, similar to PV operations in operating systems. He specifies the maximum number of threads that can simultaneously access a shared resource. It allows multiple threads to access the same resource at the same time, but needs to limit the maximum number of threads that can access the resource at the same time. When creating a semaphore using CreateSemaphore (), you specify both the maximum allowed resource count and the currently available resource count. Generally, the current available resource count is configured as the maximum resource count. Each additional thread’s access to the shared resource will decrease the current available resource count by 1. As long as the current available resource count is greater than 0, the semaphore signal can be sent. However, when the current available count decreases to 0, it indicates that the number of threads currently occupying resources has reached the maximum allowed number, and other threads cannot be allowed to enter, at this time, the semaphore signal will not be issued. After a thread has processed a shared resource, it should increment the count of the currently available resource by one as it leaves via ReleaseSemaphore (). The current count of available resources can never be greater than the maximum count at any time.

There are 100 life jackets for everyone to use, and if they run out, they have to wait for someone to return them

The concept of PV operation and semaphore was developed by Dutch scientist E.W.Dijkstra. The semaphore S is an integer. If S is greater than or equal to zero, it represents the number of resource entities available to concurrent processes, but if S is less than zero, it represents the number of processes waiting to use shared resources.

P operation application resource: (1) S minus 1; (2) If S minus 1 is still greater than or equal to zero, the process continues to execute; (3) If S minus 1 is less than zero, the process will be blocked and enter the queue corresponding to the signal, and then turn to process scheduling. (1) S + 1; (2) If the sum result is greater than zero, the process continues to execute; (3) If the summation result is less than or equal to zero, a waiting process will be awakened from the waiting queue of the signal, and then the original process will be returned to continue execution or transfer to process scheduling. Semaphores contain several operation primitives: CreateSemaphore () creates a semaphore OpenSemaphore () opens a semaphore ReleaseSemaphore () releases a semaphore WaitForSingleObject () Waits for a semaphoreCopy the code
// HANDLE global_Semephore; Char global_Array[256]; void InitializeArray() { for(int i = 0; i<256; i ) { global_Array[i]=I; }} // thread 1 UINT Global_ThreadOne(LPVOID pParam) {CEdit * PTR =(CEdit *)pParam; ptr->SetWindowText(""); WaitForSingleObject(global_Semephore, INFINITE); for(int i = 0; i<256; i ) { global_Array[i]=O; ptr->SetWindowText(global_Array); Sleep(10); ReleaseSemaphore(global_Semephore, 1, NULL); return 0; } UINT Global_ThreadTwo(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); WaitForSingleObject(global_Semephore, INFINITE); for(int i = 0; i<256; i ) { global_Array[i]=T; ptr->SetWindowText(global_Array); Sleep(10); } ReleaseSemaphore(global_Semephore, 1, NULL); return 0; } UINT Global_ThreadThree(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); WaitForSingleObject(global_Semephore, INFINITE); for(int i = 0; i<256; i ) { global_Array[i]=H; ptr->SetWindowText(global_Array); Sleep(10); } ReleaseSemaphore(global_Semephore, 1, NULL); return 0; } void CSemaphoreDlg: : OnBnClickedButtonOne () {/ / configuration semaphore 1 resources 1 at the same time can only have a thread access global_Semephore = CreateSemaphore (NULL, 1, 1, NULL); this->StartThread(); // TODO: Add your the control notification handler code here} void CSemaphoreDlg: : OnBnClickedButtonTwo () {/ / configuration 2 semaphore two resources Global_Semephore = CreateSemaphore(NULL, 2, 2, NULL); this->StartThread(); // TODO: Add your the control notification handler code here} void CSemaphoreDlg: : OnBnClickedButtonThree () {/ / configuration semaphore 3 three resources Global_Semephore = CreateSemaphore(NULL, 3, 3, NULL); this->StartThread(); // TODO: Add your control notification handler code here }Copy the code

The semaphore features make it more suitable for synchronization of threads in Socket programs. For example, HTTP server on the network to the same time limit the number of users access to the same page, then to each user page request to the server configuration a thread, while the page is to protect the Shared resources, through the use of a semaphore of thread synchronization to ensure that no matter how many users at any moment to access a page, Only threads that are no more than the maximum number of users can access the page, and other access attempts are suspended until a user exits the page.

Event

Event objects can also keep threads synchronized by notifying actions. And can realize the thread synchronization operation in different processes. I am at the head of the Yangtze River, you are at the end of the Yangtze River, we write letters to communicate, you have something to write to me, I have been waiting, this letter is the event, and then I know your situation, the implementation of corresponding operations. In the same way, I write to you.

Semaphores contain several operation primitives: CreateEvent () creates a semaphore OpenEvent () opens an event SetEvent () returns the event WaitForSingleObject () to wait for an event WaitForMultipleObjects () waits for multiple events. WaitForMultipleObjects (IN DWORD nCount, // Wait for the number of handles IN CONST HANDLE *lpHandles, // Pointer to HANDLE array IN BOOL bWaitAll, // Full wait flag, TRUE when any object is notified, FALSE when any object is notified. If the wait times out, the function returns WAIT_TIMEOUT. )Copy the code
// HANDLE global_Events[2]; Char global_Array[256]; void InitializeArray() { for(int i = 0; i<256; i ) { global_Array[i]=I; } } UINT Global_ThreadOne(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); for(int i = 0; i<256; i ) { global_Array[i]=O; ptr->SetWindowText(global_Array); Sleep(10); } // return SetEvent(global_Events[0]); return 0; } UINT Global_ThreadTwo(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); for(int i = 0; i<256; i ) { global_Array[i]=T; ptr->SetWindowText(global_Array); Sleep(10); } // return SetEvent(global_Events[1]); return 0; } UINT Global_ThreadThree(LPVOID pParam) { CEdit *ptr=(CEdit *)pParam; ptr->SetWindowText(""); // Wait for both events to be set back to WaitForMultipleObjects(2, global_Events, true, INFINITE); for(int i = 0; i<256; i ) { global_Array[i]=H; ptr->SetWindowText(global_Array); Sleep(10); } return 0; } void CEventDlg::OnBnClickedButtonStart() { for (int i = 0; i < 2; Global_Events [I]=CreateEvent(NULL,false,false,NULL); } CWinThread *ptrOne = AfxBeginThread(Global_ThreadOne, &m_One, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); ptrOne->ResumeThread(); //Start the second Thread CWinThread *ptrTwo = AfxBeginThread(Global_ThreadTwo, &m_Two, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); ptrTwo->ResumeThread(); //Start the Third Thread CWinThread *ptrThree = AfxBeginThread(Global_ThreadThree, &m_Three, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); ptrThree->ResumeThread(); // TODO: Add your control notification handler code here }Copy the code

Event can realize synchronization operation of different threads in different processes, and can easily realize priority comparison wait operation of multiple threads, for example, write multiple WaitForSingleObject to replace WaitForMultipleObjects to make programming more flexible.

The queue

The best, safest, but slowest, most resource-intensive method.

For example, when you buy a hamburger in KFC, everyone grabs the waiter at the front desk, and if the waiter ignores you, you can go away. Although you only deal with one person at a time, it reduces the time for calling the next person and saves the address of the store. Another way is that everyone comes to line up and occupies more space, but in a very orderly way, one buys the next one.

Conclusion:

1. Mutexes are similar to critical sections, but they are namable, meaning they can be used across processes. Creating a mutex requires more resources, so using critical sections provides a speed advantage and reduces resource usage if only for use within a process. Because a mutex is a cross-process mutex and once it’s created, it can be opened by name.

2. Mutex, Semaphore, and events can all be used to synchronize data across processes. Other objects are not related to data synchronization, but for processes and threads, they are unsignaled if they are running and signaled when they exit. So you can use WaitForSingleObject to wait for the process and thread to exit.

3. Resources can be specified by the mutex is an exclusive use, but if there are a kind of situation cannot be handled by the mutex, such as a user bought a now three concurrent access permission of the database system, can according to customer’s purchase access permission number to determine how many thread/process can carry out database operations at the same time, There is no way to do this with mutex, so semaphores can be a resource counter.

conclusion

  • If something is wrong, please point it out.
  • If you don’t understand, please point out and LET me add chestnuts.
  • If you feel OK, you can like it and let more people see it.