Win32 - 多线程之线程同步
上一篇我们讲到:有一个全局变量`long long num = 0;`,然后创建了50个线程,其中一半执行`threadInc`函数,对num进行加1操作,另一半执行`threadDes`函数,进行减1操作。每个线程循环50万次,所以理论上如果没有任何竞争的话,最后的结果应该是0,因为加减次数相同。但实际运行的时候,结果可能不是0,而是其他数值,这说明存在数据竞争的问题。
为了解决多线程并发访问全局变量导致的数据竞争问题,可以使用 Windows API 的互斥对象(Mutex)来同步线程操作。
1、CreateMutex
CreateMutex 是 Windows API 中用于创建或打开一个互斥体(Mutex)对象的函数,其原型如下:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性(通常为 NULL)
BOOL bInitialOwner, // 初始所有权(是否立即拥有互斥体)
LPCSTR lpName // 互斥体名称(跨进程标识,可为 NULL)
);
参数说明
-
lpMutexAttributes-
类型:
LPSECURITY_ATTRIBUTES(指向SECURITY_ATTRIBUTES结构的指针) -
作用:定义互斥体的安全属性(如继承性),通常设为
NULL,表示使用默认安全设置。
-
-
bInitialOwner-
类型:
BOOL -
作用:指定调用线程是否立即拥有互斥体的所有权。
-
TRUE:调用线程直接获得互斥体,需手动调用ReleaseMutex释放。 -
FALSE(推荐):互斥体初始处于未锁定状态,线程需通过WaitForSingleObject请求所有权。
-
-
-
lpName-
类型:
LPCSTR(常量字符串指针) -
作用:为互斥体命名,用于跨进程共享。
-
非空:创建命名互斥体(其他进程可通过相同名称访问)。
-
NULL:创建未命名的互斥体(仅限同一进程内使用)。
-
-
使用步骤:
(1)创建互斥体
在 main 函数中使用 CreateMutex 创建互斥体:
hMutex = CreateMutex(NULL, FALSE, NULL);
-
FALSE表示主线程不立即拥有互斥体。 -
如果创建失败,通过
GetLastError()输出错误信息。
(2)线程函数中加锁/解锁
在 threadInc 和 threadDes 的循环中,每次操作 num 前加锁,操作后解锁:
WaitForSingleObject(hMutex, INFINITE); // 请求锁
num += 1; // 或 num -= 1
ReleaseMutex(hMutex); // 释放锁
(3)关闭互斥体句柄
在所有线程结束后,关闭互斥体句柄:
CloseHandle(hMutex);
以下是修改后的代码:
#include <stdio.h>
#include <Windows.h>
#include <process.h>
#define NUM_THREAD 50
unsigned WINAPI threadInc(void* arg); // 加一操作
unsigned WINAPI threadDes(void* arg); // 减一操作
// 全局变量
long long num = 0;
HANDLE hMutex; // 互斥体句柄
int main(void) {
HANDLE tHandles[NUM_THREAD];
// 创建互斥体(未命名,初始状态为未锁定)
hMutex = CreateMutex(NULL, FALSE, NULL);
if (hMutex == NULL) {
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
// 创建50个线程(交替执行加/减操作)
for (int i = 0; i < NUM_THREAD; i++) {
if (i % 2) {
tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
} else {
tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
}
}
// 等待所有线程结束
WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
// 关闭所有线程句柄和互斥体
for (int i = 0; i < NUM_THREAD; i++) {
CloseHandle(tHandles[i]);
}
CloseHandle(hMutex);
printf("Final result: %lld\n", num);
system("pause");
return 0;
}
// 加一操作(通过互斥体同步)
unsigned WINAPI threadInc(void* arg) {
for (int i = 0; i < 500000; i++) {
WaitForSingleObject(hMutex, INFINITE); // 请求锁
num += 1;
ReleaseMutex(hMutex); // 释放锁
}
return 0;
}
// 减一操作(通过互斥体同步)
unsigned WINAPI threadDes(void* arg) {
for (int i = 0; i < 500000; i++) {
WaitForSingleObject(hMutex, INFINITE); // 请求锁
num -= 1;
ReleaseMutex(hMutex); // 释放锁
}
return 0;
}
运行结果:


浙公网安备 33010602011771号