[Windows] thread discussion-semaphores and mutex for Thread Synchronization

Source: Internet
Author: User

This series is intended to record windwos thread-related knowledge points, including thread basics, thread scheduling, thread synchronization, TLS, thread pool, etc.

 

Semaphore Kernel Object

The semaphore kernel object is used to count resources. It contains a usage count, the maximum number of resources, and the current resource count. The maximum number of resources indicates the maximum number of resources that can be controlled by semaphores. The current number of resources indicates the number of resources available for the signal.

Imagine a scenario: To develop a server process and run a maximum of five threads at the same time to respond to client requests, a "Thread Pool" should be designed ". At the beginning, all five threads should be waiting. If a client request arrives, wake up one of the five threads to process the client request. If the number of requests at the same time is 5, five threads will be put into use, and more requests should be abandoned. That is to say, as client requests increase, the current resource count decreases accordingly.

We may need such a kernel object to implement this function: Initialize five threads and wait for a kernel object to be triggered at the same time. When a client request arrives, it tries to trigger the kernel object, in this way, one of the five threads is randomly awakened and the kernel object is automatically changed to not triggered. Determine whether the maximum value is 5. On the surface, it seems that this function can be implemented using the "automatically reset event object". Why does it involve semaphores? Because semaphores can also control how many threads can be awakened at a time !! In addition, this example is only a use of semaphores, and we will see a more practical use later.

To sum up, the semaphore kernel object is such an object: it maintains a Resource Count. When the Resource Count is greater than 0, it is in the trigger state; when the resource count is equal to 0, it is in the not trigger state; the Resource Count cannot be less than 0 or greater than the resource count limit. Demonstrate the features of this kernel object:

For example, only when the resource count is greater than 0 is the trigger status. When the resource is equal to 0, the trigger status is not triggered. When the waitforsingleobject succeeds, the Resource Count is decreased. When releasesemaphore is called, the Resource Count is increased.

The following two functions: createsemaphore and createsemaphoreex are used to create a semaphore object:

Handle winapi createsemaphore (_ in_opt lpsecurity_attributes lpsemaphoreattributes, // Kernel Object Security Descriptor _ in long linitialcount, // The initial value of Resource Count _ in long lmaximumcount, // maximum value of Resource Count _ in_opt lpctstr lpname // Kernel Object Name); handle winapi createsemaphoreex (_ in_opt lpsecurity_attributes success, _ in long linitialcount, _ in long lmaximumcount, _ in_opt lptstr lpname, _ reserved DWORD dwflags, _ in DWORD dwdesiredaccess );

Any process can use opensemaphore to obtain a named semaphore:

Handle winapi opensemaphore (_ in DWORD dwdesiredaccess, _ in bool binherithandle, _ in lpctstr lpname );

The thread calls releasesemaphore to increase the resource count. Instead of increasing by 1 at a time, you can set any increment value. When the resource upper limit is to be exceeded, releasesemaphore returns false.

 
Bool winapi releasesemaphore (_ in handle hsemaphore, _ in long lreleasecount, // you can set the incremental value _ out_opt lplong lppreviouscount // return the previous Resource Count );

 

Mutex Kernel Object

Mutex is used to ensure that a thread exclusively accesses a resource. The mutex contains a count, a thread ID, and a recursive count. The mutex performs almost the same as the key segment because it records the thread ID and recursive count, so that the mutex can support recursive calls ). The mutex rule is very simple: if the thread ID is 0 (that is, no thread excludes it), it is in the trigger state, any thread that tries to wait for the object will obtain the exclusive access to the resource. If the thread ID is not 0, it is in the not triggered State, and any thread that tries to wait for the object will wait.

You can use createmutex or createmutexex to create a mutex object:

 
Handle winapi createmutex (_ in_opt lpsecurity_attributes lpmutexattributes, _ in bool binitialowner, // initialize the object state. If it is set to false, it is initialized to the trigger state. If it is set to true, the thread ID of the object will be set to the current call thread and initialized to not-triggered _ in_opt lpctstr lpname); handle winapi createmutexex (_ in_opt lpsecurity_attributes lpmutexattributes, _ in_opt lptstr lpname, _ in DWORD dwflags, _ in DWORD dwdesiredaccess );

As always, openmutex is used to open a named mutex kernel object:

Handle winapi openmutex (_ in DWORD dwdesiredaccess, _ in bool binherithandle, _ in lpctstr lpname );

After obtaining access to exclusive resources, the thread can normally execute related logic. When the mutex object needs to be released, it can call releasemutex:

 
Bool winapi releasemutex (_ in handle hmutex );

Different from other kernel objects, mutex records which thread occupies the shared resources. Combined with recursive counting, the same thread can continue to access the shared resources after obtaining the shared resources, this behavior is like a key segment. However, the mutex volume and key segment are essentially different. The key segment is the thread synchronization method in user mode, while the mutex volume is the thread synchronization method in kernel mode.

 

After introducing these two kernel objects, let's think about a scenario designed in the SLIM read/write lock of Thread Synchronization in [windows] thread: there is a shared queue, two server threads are responsible for reading and processing the entries in the queue, and two client threads are responsible for writing the entries in the queue for processing by the service tip thread. When there are no entries in the queue, the server thread should be suspended, it is awakened only when an entry enters. On the other hand, when the queue is full, the client thread should be suspended until the server processes at least one entry to release at least one entry.

Now we can use semaphores and mutex to implement the same function. The following flowchart shows the logic of the client writing thread and the server reading thread respectively:

1. create a mutex object m_hmtxq and initialize it to the untriggered status. then create a semaphore object, set the maximum resource count to the queue length, and initialize the Resource Count to 0, exactly represents the number of queue elements.

 
M_hmtxq = createmutex (null, false, null); m_hsemnumelements = createsemaphore (null, 0, nmaxelements, null );

2. design the core logic of the client, for example:

Watiforsingleobject: attempts to obtain the queue's exclusive access permission. This queue should be exclusively read or written by the thread. Therefore, mutex objects are used for synchronization;

Releasesemaphore: attempts to add a Resource Count to indicate that the client wants to add an element to the queue. Of course, the queue may be full now and the corresponding resource count has reached the count limit, in this case, releasesemaphore returns false, so that the client cannot Insert elements like those in the queue. Otherwise, if releasesemaphore returns true, it indicates that the queue is not full, and the client can insert elements into the queue.

Releasemutex: whether the client can insert elements like a queue or not, the mutex object should be released after the access is completed so that other threads can enter critical resources.

3. Design the core server logic, for example:

Watiforsingleobject: attempts to obtain the queue's exclusive access permission. This queue should be exclusively read or written by the thread. Therefore, mutex objects are used for synchronization;

Waitforsingleobject (m_hsemnumelements ...) : Try to check whether the semaphore object is in the trigger state. Only the semaphore object in the trigger state can be entered by the thread. This means that the server can read any element in the queue (resource> 0, trigger State. Otherwise, if there are no elements in the queue (resource = 0, not triggered), the server will not be able to access the queue for the time being, and the mutex should be released immediately.

Releasemutex: whether the client can insert elements like a queue or not, the mutex object should be released after the access is completed so that other threads can enter critical resources.

 

Labor fruit, reproduced please indicate the source: http://www.cnblogs.com/P_Chou/archive/2012/07/13/semaphore-and-mutex-in-thread-sync.html

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.