windows核心编程之线程同步



来源:微信公众号「编程学习基地」

线程同步

线程不同步会出现什么情况呢?

#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

猜你喜欢

转载自blog.csdn.net/qq_44519484/article/details/109678961