9.5 Semaphore Kernel Object (Semaphore)
(1) The composition of the semaphore
① Counter: The number of times that the kernel object was used
② Maximum number of resources: identifies the maximum number of resources that the semaphore can control (signed 32-bit)
③ Current number of resources : Identifies the number of currently available resources (signed 32-bit)
(2) Rules for the use of semaphores
① if the current resource count is >0, then the semaphore is in a triggered state , indicating that there are resources available .
② if the current resource count is =0, then the semaphore is not in the triggered state , indicating that no resources are available .
The ③ system will never change the current resource count to negative;
④ the current resource count is never greater than the maximum resource count
(3) Usage of the semaphore
(4) Correlation function
① Create Semaphore CreateSemaphore
Parameters |
description |
PSA |
Security properties |
lInitialCount |
How many resources are available? /strong> . If the value is set is 0 , which means no resources available , at which time Semaphore is not triggered , any thread waiting for the number of signals will Enter wait status . You can later call ReleaseSemaphore to increase the available resources and change to the trigger state. |
lMaximumCount |
Maximum number of resources to process |
Pszname |
Semaphore name |
② Increase signal Volume: ReleaseSemaphore
Parameters |
Describe |
Hsemaphore |
Semaphore handle |
lReleaseCount |
Add the lReleaseCount value to the current resource count of the semaphore |
Plpreviouscount |
Returns the original value of the current resource count, usually filled with null |
★ Call ReleaseSemaphore to get the original value of the resource count, but at the same time increase the count value of the current resource. There is currently no way to get the number of available resources for a semaphore without changing the current resource count value. (Even if the lreleasecount filled in 0 is not available!) )
Wait functions such as ③wait*: When a thread calls a wait function, if the semaphore is in the trigger State (the available resource is greater than 0), the thread obtains a resource for the semaphore and the number of available resources is reduced by 1, while continuing execution . If the semaphore is in a non-triggered state , the thread enters the wait state . Until other threads release resources.
"Semaphore Program"
#include <windows.h>#include<tchar.h>#include<locale.h>////////////////////////////////////////////////////////////////////////////a restaurant that can only accommodate 10 guests. 12 Customers#defineMax_sem_count 10#defineThreadCount 12//////////////////////////////////////////////////////////////////////////HANDLE G_hsemaphore =Null;dword WINAPI ThreadProc (LPVOID pvparam);//////////////////////////////////////////////////////////////////////////int_tmain () {_tsetlocale (Lc_all, _t ("CHS")); HANDLE Athread[threadcount]={NULL}; DWORD dwThreadID=0; G_hsemaphore=CreateSemaphore (null, max_sem_count, max_sem_count, NULL); //The following two sentences are the same as the implementation of the above sentence, first create a semaphore without resources, and then increase the resources//G_hsemaphore = CreateSemaphore (null, 0, max_sem_count, NULL); //ReleaseSemaphore (G_hsemaphore, Max_sem_count, NULL); if(NULL = =G_hsemaphore) {_tprintf (_t ("failed to create semaphore:%d\n"), GetLastError ()); return-1; } //Create 12 Threads for(inti =0; I < threadcount;i++) {Athread[i]= CreateThread (NULL,0, (lpthread_start_routine) ThreadProc, NULL,0,&dwThreadID); if(Athread[i] = =NULL) {_tprintf (_t ("failed to create thread:%d\n"), GetLastError ()); return-1; } } //wait for all threads to endwaitformultipleobjects (ThreadCount, Athread, TRUE, INFINITE); //Close all child threads for(inti =0; I < threadcount;i++) {CloseHandle (athread[i]); } //off SemaphoreCloseHandle (G_hsemaphore); _tsystem (_t ("PAUSE")); return 0;}//Thread FunctionsDWORD WINAPI ThreadProc (LPVOID pvparam) {DWORD Dwwaitresult; BOOL bcontinue=TRUE; LONG Lprevcount=0; while(bcontinue) {//wait for the resource to return immediatelyDwwaitresult = WaitForSingleObject (G_hsemaphore,0L); Switch(dwwaitresult) { Casewait_object_0:bcontinue=FALSE; _tprintf (_t ("thread%d: Wait for success! \ n"), GetCurrentThreadID ()); Sleep ( -); if(! ReleaseSemaphore (G_hsemaphore,1, &Lprevcount)) {_tprintf (_t ("releasesemaphore Failure:%d! \ n"), GetLastError ()); } //_tprintf (_t ("Thread%d: Waiting for success, currently available resources%d! \ n "), GetCurrentThreadID (), lprevcount+1); Break; Casewait_timeout: _tprintf (_t ("Thread%d: Wait timeout! \ n"), GetCurrentThreadID ()); Break; }} _tprintf (_t ("thread%d: Exit \ n"), GetCurrentThreadID ()); return 0;}
9.6 Mutex Kernel object (mutex)
(1) The composition of the mutex amount
① usage count: With other kernel objects, there is a usage count
② thread ID: Identifies which thread is currently occupying this mutex
③ recursive count: The number of times that the thread occupies a mutex
(2) Rules for mutex
① If the thread ID is 0 (that is, an invalid ID), then the mutex is not occupied by any thread, that is, in the triggering state
② If the thread ID is a non-0 value, it means that the line Cheng occupies the mutex, and it is in a non-triggering state.
③ other kernel objects only record which threads are waiting, but the mutex also records which thread is waiting for success. This allows it to be obtained by the thread when it is not triggered . When any thread attempts to invoke Releasmutex, the function checks whether the ID of the calling thread is the same as the ID that is stored inside the mutex. If consistent, the recursive count is decremented. Otherwise, false is returned, and the call to GetLastError will get Error_not_owner.
(3) How to use the mutex amount
① Create Mutex: Createmutext (Psa,binitialowner,pszname), where Binitialowner is true indicates that the calling thread ID is set to the internal thread ID of the mutex, the recursive count plus 1. Otherwise, the mutex is not occupied (in a triggered state)
② release Mutex: ReleaseMutex, recursive count minus 1, when the recursive count is 0 o'clock, the thread ID is set to 0. Here the mutex is triggered.
9.6.1 mutex is "abandonment problem"
If a mutex-occupying thread terminates prematurely before releasing the mutex, this behavior is called a mutex being "abandoned" (abandoned), and the system automatically sets the thread ID and recursive count of the mutex to 0. Again "fairly" wakes a waiting thread, but then the awakened thread returns from wait* no longer wait_object_0, but returns wait_abandonedto indicate that the thread has waited for an abandoned mutex. So at this point the resource being protected by the mutex is in what state , the awakened thread does not know and asks the application to decide what to do.
9.6.2 the comparison between mutex and key segment
Characteristics |
Mutex Amount |
Key segment |
Performance |
Slow |
Fast |
Whether it can be used across processes |
Is |
Whether |
Sound time |
HANDLE HMTX |
Critical_section CS; |
Initialization |
CreateMutex |
InitializeCriticalSection |
Clean |
CloseHandle |
DeleteCriticalSection |
Infinite waiting |
wait* (Hmtx,infinite) |
EnterCriticalSection (&CS) |
0 waiting |
wait* (hmtx,0) |
TryEnterCriticalSection |
Wait for any length of time |
wait* (Htmx,dwmilliseconds) |
Not supported |
Release |
ReleaseMutex |
LeaveCriticalSection |
Whether you can wait for other kernel objects at the same time |
Is such as Waitformultipleobject |
Whether |
9th. Thread synchronization with kernel objects (3) _ Semaphore (semaphore), mutex (mutex)