Methods used for thread mutex include: Atomic lock, criticalsection, mutex ),.
The methods used for thread synchronization include event, semaphore, and timer ).
Atomic lock: we all know that simple I ++ is not an atomic operation. In fact, it is done in several steps internally. In this case, multithreading may cause problems. So we can use atomic locks, but this method has some limitations, that is, it can only be used to perform addition and subtraction of simple data operations, if it involves a complex data structure, then there will be problems.
Interlockedincrement (long volatile * addend );
Interlockeddecrement (long volatile * addend );
Interlockedexchangeadd (long volatile * addend,
Longvalue );
Interlockedexchange (long volatile * target,
Longvalue );
Example:
If no atomic lock is used:
# Include <stdio. h> # include <windows. h> # include <process. h> volatile long g_nlogincount; unsigned int _ stdcall fun (void * ppm); const DWORD thread_num = 50; unsigned int _ stdcall threadfun (void * ppm) {g_nlogincount ++; return 0;} int main () {int num = 20; while (Num --) {g_nlogincount = 0; int I; handle [thread_num]; for (I = 0; I <thread_num; I ++) handle [I] = (handle) _ beginthreadex (null, 0, threadfun, null, 0, null); waitformultipleobjects (thread_num, handle, true, infinite); for (I = 0; I <thread_num; I ++) {closehandle (handle [I]);} printf ("% d threads execute I ++, the result is % d \ n ", thread_num, g_nlogincount);} return 0 ;}
Here, I will explain why we have made several threads and made them so complicated: A WHILE LOOP and a for loop. This is because we cannot create multiple threads at a time. Otherwise, problems may occur, you can try to create 100 threads in sequence, which may cause problems. It seems that up to 64 threads can be created at a time. So this complicated method is used here.
Use of Atomic locks:
unsigned int __stdcall ThreadFun(void *pPM){g_nLoginCount++;InterlockedIncrement(&g_nLoginCount);return 0;}
Criticalsection is usually used when threads are mutually exclusive.
Void
Initializecriticalsection (maid); ----------- initialize Key Areas
Void
Deletecriticalsection (maid section );----------- Delete key areas
Void
Entercriticalsection (maid section );----------- Enter key areasVoid
Leavecriticalsection (maid section );----------- Exit Key Areas
General error:
# Include <stdio. h> # include <process. h> # include <windows. h> long g_nnum; unsigned int _ stdcall fun (void * ppm); const int thread_num = 10; int main () {handle [thread_num]; g_nnum = 0; int I = 0; while (I <thread_num) {handle [I ++] = (handle) _ beginthreadex (null, 0, fun, null, 0, null );} waitformultipleobjects (thread_num, handle, true, infinite); for (I = 0; I <sizeof (handle); I ++) {closehandle (handle [I]);} return 0;} unsigned int _ stdcall fun (void * ppm) {sleep (50); g_nnum ++; sleep (0); printf ("the current count is: % d \ n ", g_nnum); Return 0 ;}
When key areas are used:
CRITICAL_SECTION g_csThreadCode;InitializeCriticalSection(&g_csThreadCode);DeleteCriticalSection(&g_csThreadCode);
Unsigned int _ stdcall fun (void * ppm) {sleep (50); entercriticalsection (& g_csthreadcode); g_nnum ++; sleep (0); printf ("the current count is: % d \ n ", g_nnum); leavecriticalsection (& g_csthreadcode); Return 0 ;}
Event)
Handlecreateevent (
Lpsecurity_attributeslpeventattributes,
Boolbmanualreset,
Boolbinitialstate,
Lpctstrlpname
); --------- Create an event.
Handleopenevent (
Dworddwdesiredaccess,
Boolbinherithandle,
Lpctstrlpname
); ------------ Open the event
Boolsetevent (handlehevent); ---------- trigger event
Boolresetevent (handlehevent); ----------- set the event to not triggered
Generally, events are divided into two types:Manual location event (true)And the auto-location event (false), which is specified in the second parameter of the createevent function. Their differences are:When setevent is called, all threads waiting for the event to be activatedAfter the setevent is called, only one thread is activated. AutomaticThe reset event does not need to call the resetevent function, because the system will automatically help you set it to not triggered, and the manual reset event also needs to call the resetevent function.
Before presenting events, let's talk about the differences between thread mutex and thread synchronization. In my understanding, thread mutex is equivalent to two writers writing a file at the same time, causing confusion. Thread Synchronization is equivalent to when a reader is reading a file, the confusion caused by writing constantly. In the past, we passed the thread ID. (The main thread writes data and the sub-thread reads data ).
Events Not used:
# Include <stdio. h> # include <process. h> # include <windows. h> long g_nnum; unsigned int _ stdcall fun (void * ppm); const int thread_num = 10; critical_section g_csthreadcode; int main () {initializecriticalsection (& g_csthreadcode ); handle handle [thread_num]; g_nnum = 0; int I = 0; while (I <thread_num) {handle [I ++] = (handle) _ beginthreadex (null, 0, fun, & I, 0, null) ;}waitformultipleobjects (thread_num, handle, true, infinite); for (I = 0; I <sizeof (handle); I ++) {closehandle (handle [I]);} deletecriticalsection (& g_csthreadcode); Return 0;} unsigned int _ stdcall fun (void * ppm) {int nthreadnum = * (int *) ppm; sleep (50); entercriticalsection (& g_csthreadcode); g_nnum ++; sleep (0); printf ("current thread: % d, current count: % d \ n ", nthreadnum, g_nnum); leavecriticalsection (& g_csthreadcode); Return 0 ;}
The thread ID does not meet the requirements ..
Event usage: (Here we use manual event settings, so we need to call resetevent ).
# Include <stdio. h> # include <process. h> # include <windows. h> long g_nnum; unsigned int _ stdcall fun (void * ppm); const int thread_num = 10; handle g_hthreadevent; critical_section g_csthreadcode; int main () {g_hthreadevent = createevent (null, true, false, null); initializecriticalsection (& g_csthreadcode); handle [thread_num]; g_nnum = 0; int I = 0; while (I <thread_num) {handle [I] = (handle) _ beginthreadex (null, 0, fun, & I, 0, null); waitforsingleobject (g_hthreadevent, infinite); resetevent (g_hthreadevent ); I ++;} waitformultipleobjects (thread_num, handle, true, infinite); for (I = 0; I <sizeof (handle); I ++) {closehandle (handle [I]);} closehandle (g_hthreadevent); deletecriticalsection (& g_csthreadcode); Return 0;} unsigned int _ stdcall fun (void * ppm) {int nthreadnum = * (int *) ppm; setevent (g_hthreadevent); sleep (50); entercriticalsection (& g_csthreadcode); g_nnum ++; sleep (0 ); printf ("current thread: % d, current count: % d \ n", nthreadnum, g_nnum); leavecriticalsection (& g_csthreadcode); Return 0 ;}
The thread ID meets the requirements ..
Mutex
# Include <stdio. h> # include <process. h> # include <windows. h> long g_nnum; unsigned int _ stdcall fun (void * ppm); const int thread_num = 10; handle g_mutex; int main () {g_mutex = createmutex (null, false, null); handle [thread_num]; g_nnum = 0; int I = 0; while (I <thread_num) {handle [I ++] = (handle) _ beginthreadex (null, 0, fun, & I, 0, null);} waitformultipleobjects (thread_num, handle, true, infinite); closehandle (g_mutex); for (I = 0; I <thread_num; I ++) closehandle (handle [I]); Return 0;} unsigned int _ stdcall fun (void * ppm) {sleep (50); waitforsingleobject (g_mutex, infinite ); g_nnum ++; sleep (0); printf ("current count: % d \ n", g_nnum); releasemutex (g_mutex); Return 0 ;}
Semaphores (semaphore)
Handle
Createsemaphore (
Lpsecurity_attributes l1_maphoreattributes,
Long linitialcount,
Long lmaximumcount,
Lptstr lpname
); ---------------- Create a semaphore
Handle
Opensemaphore (
DWORD dwdesiredaccess,
Bool binherithandle,
Lptstr lpname
); ---------------- Open the semaphore
Bool
Releasesemaphore (
Handle hsemaphore,
Long lreleasecount,
Lplong lppreviouscount
); ------------------ Release the semaphore
Increase of semaphores: releasesemaphore. Semaphore subtraction: waitforsingleobject (..); when a semaphore is requested, if the current semaphore is 0, that is, it is not triggered, then the thread enters the blocking state until the signal value is greater than 0, this function returns, the thread enters the scheduling state, at the same time, the signal value is reduced by one.
Note: The semaphore value cannot be less than 0.
# Include <stdio. h> # include <process. h> # include <windows. h> long g_nnum; unsigned int _ stdcall fun (void * ppm); const int thread_num = 10; handle g_semaphore; critical_section g_criticalsection; int main () {g_semaphore = createsemaphore (null, 0, 1, null); initializecriticalsection (& g_criticalsection); handle [thread_num]; g_nnum = 0; int I = 0; while (I <thread_num) {handle [I] = (handle) _ beginthreadex (null, 0, fun, & I, 0, null); waitforsingleobject (g_semaphore, infinite); ++ I ;} waitformultipleobjects (thread_num, handle, true, infinite); deletecriticalsection (& g_criticalsection); closehandle (g_semaphore); for (I = 0; I <thread_num; I ++) closehandle (handle [I]); Return 0;} unsigned int _ stdcall fun (void * ppm) {int nthreadnum = * (int *) ppm; releasesemaphore (g_semaphore, 1, null); sleep (50); entercriticalsection (& g_criticalsection); ++ g_nnum; sleep (0); printf ("the current thread is: % d, and the current count is: % d \ n ", nthreadnum, g_nnum); leavecriticalsection (& g_criticalsection); Return 0 ;}