临界区 线程锁相关API 每个线程都有自己的栈,而局部变量是储存在栈中的,这就意味着每个线程都有一分自己的“局部变量”,如果线程仅仅使用“局部变量”那么就不存在线程安全问题。
线程锁仅仅只是防止同一进程间多线程访问同一个临界资源(一般是全局变量)
创建全局变量
初始化全局变量 1 InitializeCriticalSection(&cs);
实现临界区 1 2 3 EnterCriticalSection(&cs); LeaveCriticalSection(&cs);
使用C语言创建线程锁
注意,使用线程锁时要将需要使用的全局资源包含在临界区,此例中要确保count处于临界区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <stdio.h> #include <Windows.h> #include <stdlib.h> int count = 10 ;CRITICAL_SECTION cs; DWORD WINAPI ThreadProc (_In_ LPVOID lpParameter) { EnterCriticalSection(&cs); while (count > 0 ) { printf ("proc1 %d\n" , count); Sleep(200 ); count--; } LeaveCriticalSection(&cs); return 0 ; } DWORD WINAPI ThreadProc1 (_In_ LPVOID lpParameter) { EnterCriticalSection(&cs); while (count > 0 ) { printf ("proc2 %d\n" , count); Sleep(200 ); count--; } LeaveCriticalSection(&cs); return 0 ; } int main () { InitializeCriticalSection(&cs); HANDLE hThread[2 ]; hThread[0 ] = CreateThread(NULL , 0 , ThreadProc, NULL , 0 , NULL ); hThread[1 ] = CreateThread(NULL , 0 , ThreadProc1, NULL , 0 , NULL ); WaitForMultipleObjects(2 , hThread, TRUE, INFINITE); CloseHandle(hThread[0 ]); CloseHandle(hThread[1 ]); system("pause" ); }
互斥体 如果多个进程需要访问同一内核级的临界资源可以使用互斥体,线程锁只能控制同一个进程中的多个线程同时访问一个临界资源。
函数原形 1 2 3 4 5 6 HANDLE CreateMutexA ( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName ) ;
关于返回值
如果执行成功则返回互斥体的句柄,否则返回NULL,这个返回值并不能判断互斥体是否已被占用,可以调用GetLastError(),如果结果为ERROR_ALREADY_EXISTS则互斥体已被占用 官方文档: If the function succeeds, the return value is a handle to the newly created mutex object.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, and the GetLastError function returns ERROR_ALREADY_EXISTS.
互斥体和线程锁的区别
线程锁只能用于单个进程间的线程控制
互斥体可以设定等待超时,但线程锁不能
线程锁意外终结时,Mutex可以避免无限等待
Mutex效率没有线程锁高
使用C语言创建互斥体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <stdio.h> #include <Windows.h> #include <stdlib.h> int main () { HANDLE hMutex = CreateMutex(NULL , FALSE, L"互斥体" ); DWORD dwErr = GetLastError(); if (hMutex) { if (dwErr == ERROR_ALREADY_EXISTS) { CloseHandle(hMutex); return 0 ; } } else { printf ("Failed to create, program exits" ); CloseHandle(hMutex); return 0 ; } while (true ) { printf ("程序执行中\n" ); Sleep(1000 ); } system("pause" ); }
线程同步 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达才被唤醒。
同步 = 互斥 + 有序
使用互斥实现线程同步 使用互斥实现线程同步会浪费CPU时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <stdio.h> #include <Windows.h> #include <stdlib.h> HANDLE hMutex; int max = 10 ;int number = 0 ;DWORD WINAPI threadProduct (_In_ LPVOID lpParameter) { for (int i = 0 ; i < max; i++) { WaitForSingleObject(hMutex, INFINITE); if (number == 0 ) { number = 1 ; DWORD id = GetCurrentThreadId(); printf ("生产者%d将%d放入缓冲区\n" , id, number); } else { printf ("-----------------" ); i--; } ReleaseMutex(hMutex); } return 0 ; } DWORD WINAPI threadConsumer (_In_ LPVOID lpParameter) { for (int i = 0 ; i < max; i++) { WaitForSingleObject(hMutex, INFINITE); if (number == 1 ) { number = 0 ; DWORD id = GetCurrentThreadId(); printf ("消费者%d将%d放入缓冲区\n" , id, number); } else { printf ("-----------------" ); i--; } ReleaseMutex(hMutex); } return 0 ; } int main () { HANDLE hTread[2 ]; hMutex = CreateMutex(NULL , FALSE, NULL ); hTread[0 ] = CreateThread(NULL , 0 , threadProduct, NULL , 0 , NULL ); hTread[1 ] = CreateThread(NULL , 0 , threadConsumer, NULL , 0 , NULL ); WaitForMultipleObjects(2 , hTread, TRUE, INFINITE); CloseHandle(hTread[0 ]); CloseHandle(hTread[1 ]); CloseHandle(hMutex); system("pause" ); }
使用事件实现线程同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <stdio.h> #include <Windows.h> #include <stdlib.h> HANDLE hMutex; HANDLE hSet; HANDLE hClear; int max = 10 ;int number = 0 ;DWORD WINAPI threadProduct (_In_ LPVOID lpParameter) { for (int i = 0 ; i < max; i++) { WaitForSingleObject(hSet, INFINITE); number = 1 ; DWORD id = GetCurrentThreadId(); printf ("生产者%d将%d放入缓冲区\n" , id, number); SetEvent(hClear); } return 0 ; } DWORD WINAPI threadConsumer (_In_ LPVOID lpParameter) { for (int i = 0 ; i < max; i++) { WaitForSingleObject(hClear, INFINITE); number = 0 ; DWORD id = GetCurrentThreadId(); printf ("----消费者%d将%d放入缓冲区\n" , id, number); SetEvent(hSet); } return 0 ; } int main () { HANDLE hTread[2 ]; hSet = CreateEvent(NULL , FALSE, TRUE, NULL ); hClear = CreateEvent(NULL , FALSE, FALSE, NULL ); hTread[0 ] = CreateThread(NULL , 0 , threadProduct, NULL , 0 , NULL ); hTread[1 ] = CreateThread(NULL , 0 , threadConsumer, NULL , 0 , NULL ); WaitForMultipleObjects(2 , hTread, TRUE, INFINITE); CloseHandle(hTread[0 ]); CloseHandle(hTread[1 ]); CloseHandle(hSet); CloseHandle(hClear); system("pause" ); }