来源:微信公众号「编程学习基地」
线程同步
线程不同步会出现什么情况呢?
#include <stdio.h>
#include <windows.h>
static int count = 20;
const unsigned int MAX = 4;
// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
while (count >= 0)
{
printf("coutn:%d \tThread:%d\n", count--, GetCurrentThreadId());
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThread[MAX];
DWORD dwThreadId;
// 创建一个线程
hThread[0] = CreateThread(
NULL, // 默认安全属性
NULL, // 默认堆栈大小
ThreadProc, // 线程入口地址(执行线程的函数)
NULL, // 传给函数的参数
0, // 指定线程立即运行
&dwThreadId); // 返回线程的ID号
hThread[1] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[2] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[3] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
// 等待新线程运行结束
WaitForMultipleObjects(MAX, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
for (int i = 0; i < MAX; i++)
{
CloseHandle(hThread[i]);
}
return 0;
}
运行结果:
coutn:20 Thread:9104
coutn:18 Thread:9104
coutn:17 Thread:9104
coutn:15 Thread:14248
coutn:13 Thread:14248
coutn:16 Thread:10472
coutn:11 Thread:10472
coutn:10 Thread:10472
coutn:9 Thread:10472
coutn:8 Thread:10472
coutn:7 Thread:10472
coutn:6 Thread:10472
coutn:5 Thread:10472
coutn:4 Thread:10472
coutn:3 Thread:10472
coutn:2 Thread:10472
coutn:1 Thread:10472
coutn:0 Thread:10472
coutn:14 Thread:9104
coutn:19 Thread:3076
coutn:12 Thread:14248
临界区
临界区对象时定义在数据段中的一个CRITICAL_SECTION结构,通过这个结构记录一些信息,以达到在同一时间只有一个线程访问该数据段中的数据。
CRITICAL_SECTION是不能够“锁定”资源的,它能够完成的功能,是同步不同线程的代码段。
初始化临界区对象
void InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
进入离开临界区
void EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
void LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
删除临界区对象
void DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
使用示例
#include <stdio.h>
#include <windows.h>
static int count = 20;
const unsigned int MAX = 4;
CRITICAL_SECTION g_cs; //对存在同步问题的代码段使用临界区对象
// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
while (count >= 0)
{
EnterCriticalSection(&g_cs);
printf("coutn:%d \tThread:%d\n", count--, GetCurrentThreadId());
LeaveCriticalSection(&g_cs);
Sleep(1);
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThread[MAX];
DWORD dwThreadId;
// 初始化临界区对象
InitializeCriticalSection(&g_cs);
// 创建一个线程
hThread[0] = CreateThread(
NULL, // 默认安全属性
NULL, // 默认堆栈大小
ThreadProc, // 线程入口地址(执行线程的函数)
NULL, // 传给函数的参数
0, // 指定线程立即运行
&dwThreadId); // 返回线程的ID号
hThread[1] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[2] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[3] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
// 等待新线程运行结束
WaitForMultipleObjects(MAX, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
for (int i = 0; i < MAX; i++)
{
CloseHandle(hThread[i]);
}
// 删除临界区对象
DeleteCriticalSection(&g_cs);
return 0;
}
输出
coutn:20 Thread:5340
coutn:19 Thread:5808
coutn:18 Thread:3884
coutn:17 Thread:5340
coutn:16 Thread:1772
coutn:15 Thread:1772
coutn:14 Thread:5340
coutn:13 Thread:3884
coutn:12 Thread:5808
coutn:11 Thread:3884
coutn:10 Thread:5340
coutn:9 Thread:1772
coutn:8 Thread:5808
coutn:7 Thread:3884
coutn:6 Thread:5340
coutn:5 Thread:1772
coutn:4 Thread:5808
coutn:3 Thread:1772
coutn:2 Thread:3884
coutn:1 Thread:5808
coutn:0 Thread:5340
互斥函数
LONG InterlockedDecrement(
LONG volatile *Addend //指向递减的变量
);
LONG InterlockedIncrement(
LONG volatile *Addend //指向递增的变量
);
#include <stdio.h>
#include <windows.h>
static int count = 20;
const unsigned int MAX = 4;
// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
while(count >= 0)
{
InterlockedDecrement((long*)&count);
printf("coutn:%d \tThread:%d\n", count, GetCurrentThreadId());
Sleep(10);
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThread[MAX];
DWORD dwThreadId;
// 创建一个线程
hThread[0] = CreateThread(
NULL, // 默认安全属性
NULL, // 默认堆栈大小
ThreadProc, // 线程入口地址(执行线程的函数)
NULL, // 传给函数的参数
0, // 指定线程立即运行
&dwThreadId); // 返回线程的ID号
hThread[1] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[2] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[3] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
// 等待新线程运行结束
WaitForMultipleObjects(MAX, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
for (int i = 0; i < MAX; i++)
{
CloseHandle(hThread[i]);
}
return 0;
}
事件内核对象
事件内核对象是一种抽象的对象,它有受信和未授信两种状态,通过等待WaitForSingleObject
实现线程同步
HANDLE CreateEventA(
LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
BOOL bManualReset, //是否手动重置事件对象为未受信对象
BOOL bInitialState, //指定事件对象创建时的初始状态
LPCSTR lpName //事件对象的名称
);
设置内核对象状态
BOOL SetEvent(
HANDLE hEvent
);
BOOL ResetEvent(
HANDLE hEvent
);
等待事件内核对象受信
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
示例:
#include <stdio.h>
#include <windows.h>
static int count = 20;
const unsigned int MAX = 4;
HANDLE g_hEvent;
// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
while (count >= 0)
{
/*等待内核对象受信,函数调用结束内核对象被设置为未授信*/
WaitForSingleObject(g_hEvent, INFINITE);
printf("coutn:%d \tThread:%d\n", count--, GetCurrentThreadId());
SetEvent(g_hEvent); /*设置受信*/
Sleep(10);
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThread[MAX];
DWORD dwThreadId;
// 创建一个自动重置的(auto-reset events),受信的(signaled)事件内核对象
g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
// 创建一个线程
hThread[0] = CreateThread(
NULL, // 默认安全属性
NULL, // 默认堆栈大小
ThreadProc, // 线程入口地址(执行线程的函数)
NULL, // 传给函数的参数
0, // 指定线程立即运行
&dwThreadId); // 返回线程的ID号
hThread[1] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[2] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
hThread[3] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &dwThreadId);
// 等待新线程运行结束
WaitForMultipleObjects(MAX, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
for (int i = 0; i < MAX; i++)
{
CloseHandle(hThread[i]);
}
return 0;
}
输出
coutn:20 Thread:3156
coutn:19 Thread:9360
coutn:18 Thread:11444
coutn:17 Thread:17128
coutn:16 Thread:3156
coutn:15 Thread:9360
coutn:14 Thread:11444
coutn:13 Thread:17128
coutn:12 Thread:3156
coutn:11 Thread:17128
coutn:10 Thread:9360
coutn:9 Thread:11444
coutn:8 Thread:3156
coutn:7 Thread:17128
coutn:6 Thread:9360
coutn:5 Thread:11444
coutn:4 Thread:3156
coutn:3 Thread:11444
coutn:2 Thread:9360
coutn:1 Thread:17128
coutn:0 Thread:3156