#include <stdio.h>
#include <windows.h>
#include <process.h>
// 定义全局变量
CRITICAL_SECTION g_cs;
unsigned int __stdcall ThreadFun1(PVOID lpParam)
{
//申请进入临界区
EnterCriticalSection(&g_cs);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//离开临界区
LeaveCriticalSection(&g_cs);
return 0;
}
unsigned int __stdcall ThreadFun2(PVOID lpParam)
{
//申请进入临界区
EnterCriticalSection(&g_cs);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//离开临界区
LeaveCriticalSection(&g_cs);
return 0;
}
unsigned int __stdcall ThreadFun3(PVOID lpParam)
{
//申请进入临界区
EnterCriticalSection(&g_cs);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//离开临界区
LeaveCriticalSection(&g_cs);
return 0;
}
int main()
{
unsigned ThreadID1 = 0;
unsigned ThreadID2 = 0;
unsigned ThreadID3 = 0;
// 初始化临界区对象
InitializeCriticalSection(&g_cs);
//创建线程
HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, (void*)5, 0, &ThreadID1);
HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, (void*)5, 0, &ThreadID2);
HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun3, (void*)5, 0, &ThreadID3);
printf("main function thread1 id is %d\n", ThreadID1);
printf("main function thread2 id is %d\n", ThreadID2);
printf("main function thread3 id is %d\n", ThreadID3);
//永久等待线程运行结束
WaitForSingleObject(handle1, INFINITE);
WaitForSingleObject(handle2, INFINITE);
WaitForSingleObject(handle3, INFINITE);
//删除临界区对象
DeleteCriticalSection(&g_cs);
//关闭线程句柄
CloseHandle(handle1);
CloseHandle(handle2);
CloseHandle(handle3);
system("pause");
return 0;
}
运行结果
从运行结果可以看到,这三个线程之间实现了互斥,即一个线程执行完另一个线程才会执行
main function thread1 id is 21072
main function thread2 id is 41576
main function thread3 id is 16796
thread id is 21072, number is 5
thread id is 21072, number is 4
thread id is 21072, number is 3
thread id is 21072, number is 2
thread id is 21072, number is 1
thread id is 41576, number is 5
thread id is 41576, number is 4
thread id is 41576, number is 3
thread id is 41576, number is 2
thread id is 41576, number is 1
thread id is 16796, number is 5
thread id is 16796, number is 4
thread id is 16796, number is 3
thread id is 16796, number is 2
thread id is 16796, number is 1
请按任意键继续. . .
如果我们删除对线程的互斥控制,再看下执行结果,可以很清楚的看出区别
main function thread1 id is 13796
main function thread2 id is 41216
main function thread3 id is 7088
thread id is 41216, number is 5
thread id is 13796, number is 5
thread id is 7088, number is 5
thread id is 7088, number is 4
thread id is 13796, number is 4
thread id is 41216, number is 4
thread id is 7088, number is 3
thread id is 13796, number is 3
thread id is 41216, number is 3
thread id is 13796, number is 2
thread id is 41216, number is 2
thread id is 7088, number is 2
thread id is 13796, number is 1
thread id is 7088, number is 1
thread id is 41216, number is 1
请按任意键继续. . .
2.2、事件内核对象
实现步骤
全局
定义一个全局变量
主线程中
创建自动重置,未受信的事件内核对象
创建线程
触发事件
等待线程运行结束
关闭内核对象
关闭线程句柄
子线程中
等待事件触发
进行相关工作
重新触发事件
编码实现
#include <stdio.h>
#include <windows.h>
#include <process.h>
// 定义全局变量
HANDLE g_hEvent;
unsigned int __stdcall ThreadFun1(PVOID lpParam)
{
//等待事件触发
WaitForSingleObject(g_hEvent, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//重新触发事件
SetEvent(g_hEvent);
return 0;
}
unsigned int __stdcall ThreadFun2(PVOID lpParam)
{
//等待事件触发
WaitForSingleObject(g_hEvent, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//重新触发事件
SetEvent(g_hEvent);
return 0;
}
unsigned int __stdcall ThreadFun3(PVOID lpParam)
{
//等待事件触发
WaitForSingleObject(g_hEvent, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//重新触发事件
SetEvent(g_hEvent);
return 0;
}
int main()
{
unsigned ThreadID1 = 0;
unsigned ThreadID2 = 0;
unsigned ThreadID3 = 0;
// 创建自动重置,未受信的事件内核对象
g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
//创建线程
HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, (void*)5, 0, &ThreadID1);
HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, (void*)5, 0, &ThreadID2);
HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun3, (void*)5, 0, &ThreadID3);
printf("main function thread1 id is %d\n", ThreadID1);
printf("main function thread2 id is %d\n", ThreadID2);
printf("main function thread3 id is %d\n", ThreadID3);
//触发事件
SetEvent(g_hEvent);
//永久等待线程运行结束
WaitForSingleObject(handle1, INFINITE);
WaitForSingleObject(handle2, INFINITE);
WaitForSingleObject(handle3, INFINITE);
//关闭内核对象
CloseHandle(g_hEvent);
//关闭线程句柄
CloseHandle(handle1);
CloseHandle(handle2);
CloseHandle(handle3);
system("pause");
return 0;
}
运行结果
main function thread1 id is 43624
main function thread2 id is 42564
main function thread3 id is 43648
thread id is 43624, number is 5
thread id is 43624, number is 4
thread id is 43624, number is 3
thread id is 43624, number is 2
thread id is 43624, number is 1
thread id is 42564, number is 5
thread id is 42564, number is 4
thread id is 42564, number is 3
thread id is 42564, number is 2
thread id is 42564, number is 1
thread id is 43648, number is 5
thread id is 43648, number is 4
thread id is 43648, number is 3
thread id is 43648, number is 2
thread id is 43648, number is 1
请按任意键继续. . .
2.3、互斥量
实现步骤
全局
定义一个互斥量
主线程
创建互斥量
创建线程
等待线程运行结束
关闭线程句柄
删除互斥量
子线程
等待互斥量
释放互斥量
编码实现
#include <stdio.h>
#include <windows.h>
#include <process.h>
// 定义互斥量
HANDLE hMutex;
unsigned int __stdcall ThreadFun1(PVOID lpParam)
{
//等待互斥量
WaitForSingleObject(hMutex, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//释放互斥量
ReleaseMutex(hMutex);
return 0;
}
unsigned int __stdcall ThreadFun2(PVOID lpParam)
{
//等待互斥量
WaitForSingleObject(hMutex, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//释放互斥量
ReleaseMutex(hMutex);
return 0;
}
unsigned int __stdcall ThreadFun3(PVOID lpParam)
{
//等待互斥量
WaitForSingleObject(hMutex, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//释放互斥量
ReleaseMutex(hMutex);
return 0;
}
int main()
{
unsigned ThreadID1 = 0;
unsigned ThreadID2 = 0;
unsigned ThreadID3 = 0;
// 创建互斥量
hMutex = CreateMutex(NULL, FALSE, NULL);
//创建线程
HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, (void*)5, 0, &ThreadID1);
HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, (void*)5, 0, &ThreadID2);
HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun3, (void*)5, 0, &ThreadID3);
printf("main function thread1 id is %d\n", ThreadID1);
printf("main function thread2 id is %d\n", ThreadID2);
printf("main function thread3 id is %d\n", ThreadID3);
//永久等待线程运行结束
WaitForSingleObject(handle1, INFINITE);
WaitForSingleObject(handle2, INFINITE);
WaitForSingleObject(handle3, INFINITE);
//关闭线程句柄
CloseHandle(handle1);
CloseHandle(handle2);
CloseHandle(handle3);
//删除互斥量
CloseHandle(hMutex);
system("pause");
return 0;
}
运行结果
main function thread1 id is 42112
main function thread2 id is 43136
main function thread3 id is 9128
thread id is 42112, number is 5
thread id is 42112, number is 4
thread id is 42112, number is 3
thread id is 42112, number is 2
thread id is 42112, number is 1
thread id is 43136, number is 5
thread id is 43136, number is 4
thread id is 43136, number is 3
thread id is 43136, number is 2
thread id is 43136, number is 1
thread id is 9128, number is 5
thread id is 9128, number is 4
thread id is 9128, number is 3
thread id is 9128, number is 2
thread id is 9128, number is 1
请按任意键继续. . .
2.4、信号量
实现步骤
全局
定义一个信号量
主线程
创建信号量(为触发状态)
创建线程
等待线程运行结束
关闭线程句柄
删除信号量
子线程中
使信号量进入为未触发状态
进行相关工作
使信号量进入触发状态
编码实现
#include <stdio.h>
#include <windows.h>
#include <process.h>
// 定义信号量
HANDLE hSemap;
unsigned int __stdcall ThreadFun1(PVOID lpParam)
{
//使信号量进入未触发状态
WaitForSingleObject(hSemap, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//使信号量进入触发状态
ReleaseSemaphore(hSemap, 1, NULL);
return 0;
}
unsigned int __stdcall ThreadFun2(PVOID lpParam)
{
//使信号量进入未触发状态
WaitForSingleObject(hSemap, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//使信号量进入触发状态
ReleaseSemaphore(hSemap, 1, NULL);
return 0;
}
unsigned int __stdcall ThreadFun3(PVOID lpParam)
{
//使信号量进入未触发状态
WaitForSingleObject(hSemap, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//使信号量进入触发状态
ReleaseSemaphore(hSemap, 1, NULL);
return 0;
}
int main()
{
unsigned ThreadID1 = 0;
unsigned ThreadID2 = 0;
unsigned ThreadID3 = 0;
// 创建触发状态的信号量
hSemap = CreateSemaphore(NULL, 1, 1, NULL);
//创建线程
HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, (void*)5, 0, &ThreadID1);
HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, (void*)5, 0, &ThreadID2);
HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun3, (void*)5, 0, &ThreadID3);
printf("main function thread1 id is %d\n", ThreadID1);
printf("main function thread2 id is %d\n", ThreadID2);
printf("main function thread3 id is %d\n", ThreadID3);
//永久等待线程运行结束
WaitForSingleObject(handle1, INFINITE);
WaitForSingleObject(handle2, INFINITE);
WaitForSingleObject(handle3, INFINITE);
//关闭线程句柄
CloseHandle(handle1);
CloseHandle(handle2);
CloseHandle(handle3);
//删除信号量
CloseHandle(hSemap);
system("pause");
return 0;
}
运行结果
main function thread1 id is 25020
main function thread2 id is 33360
main function thread3 id is 20720
thread id is 25020, number is 5
thread id is 25020, number is 4
thread id is 25020, number is 3
thread id is 25020, number is 2
thread id is 25020, number is 1
thread id is 33360, number is 5
thread id is 33360, number is 4
thread id is 33360, number is 3
thread id is 33360, number is 2
thread id is 33360, number is 1
thread id is 20720, number is 5
thread id is 20720, number is 4
thread id is 20720, number is 3
thread id is 20720, number is 2
thread id is 20720, number is 1
请按任意键继续. . .
3、windows下的线程同步
上面介绍的四种方法都是实现线程互斥,接下来介绍线程同步,即在线程互斥基础上实现有序访问
3.1、信号量
信号量除了可以实现线程互斥,也可以实现线程同步
实现步骤
全局
定义多个信号量
主线程
创建信号量(一个为触发,其他为未触发)
创建线程
等待线程运行结束
关闭线程句柄
删除信号量
子线程中
使线程进入未触发状态
进行相关工作
使线程进入触发状态
编码实现
这里我们控制线程2先执行,再执行线程1,最后执行线程3
#include <stdio.h>
#include <windows.h>
#include <process.h>
// 定义信号量
HANDLE hSemap1;
HANDLE hSemap2;
HANDLE hSemap3;
unsigned int __stdcall ThreadFun1(PVOID lpParam)
{
//使信号量1进入未触发状态
WaitForSingleObject(hSemap1, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//使信号量3进入触发状态
ReleaseSemaphore(hSemap3, 1, NULL);
return 0;
}
unsigned int __stdcall ThreadFun2(PVOID lpParam)
{
//使信号量2进入未触发状态
WaitForSingleObject(hSemap2, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
//使信号量1进入触发状态
ReleaseSemaphore(hSemap1, 1, NULL);
return 0;
}
unsigned int __stdcall ThreadFun3(PVOID lpParam)
{
//使信号量3进入未触发状态
WaitForSingleObject(hSemap3, INFINITE);
int number = (int)lpParam;
//获取当前线程id
DWORD threadId = GetCurrentThreadId();
while (number > 0) {
printf("thread id is %d, number is %d\n", threadId, number--);
Sleep(1000);
}
return 0;
}
int main()
{
unsigned ThreadID1 = 0;
unsigned ThreadID2 = 0;
unsigned ThreadID3 = 0;
// 设置信号量1的状态为未触发状态
hSemap1 = CreateSemaphore(NULL, 0, 1, NULL);
// 设置信号量2的状态为触发状态
hSemap2 = CreateSemaphore(NULL, 1, 1, NULL);
// 设置信号量3的状态为未触发状态
hSemap3 = CreateSemaphore(NULL, 0, 1, NULL);
//创建线程
HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, (void*)5, 0, &ThreadID1);
HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, (void*)5, 0, &ThreadID2);
HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun3, (void*)5, 0, &ThreadID3);
printf("main function thread1 id is %d\n", ThreadID1);
printf("main function thread2 id is %d\n", ThreadID2);
printf("main function thread3 id is %d\n", ThreadID3);
//永久等待线程运行结束
WaitForSingleObject(handle1, INFINITE);
WaitForSingleObject(handle2, INFINITE);
WaitForSingleObject(handle3, INFINITE);
//关闭线程句柄
CloseHandle(handle1);
CloseHandle(handle2);
CloseHandle(handle3);
//删除信号量
CloseHandle(hSemap1);
CloseHandle(hSemap2);
CloseHandle(hSemap3);
system("pause");
return 0;
}
运行结果
可以看到,线程2先执行,然后线程1执行,最后线程3执行
main function thread1 id is 41360
main function thread2 id is 42024
main function thread3 id is 43380
thread id is 42024, number is 5
thread id is 42024, number is 4
thread id is 42024, number is 3
thread id is 42024, number is 2
thread id is 42024, number is 1
thread id is 41360, number is 5
thread id is 41360, number is 4
thread id is 41360, number is 3
thread id is 41360, number is 2
thread id is 41360, number is 1
thread id is 43380, number is 5
thread id is 43380, number is 4
thread id is 43380, number is 3
thread id is 43380, number is 2
thread id is 43380, number is 1
请按任意键继续. . .