线程同步

      刚开始接触线程同步问题,在工程中遇到了这些问题,之前其实根本没理解,现在才刚刚理解。

      要掌握这些问题,首先要了解线程同步和互斥的区别,最简单的区别方式是,同步是线程之间有顺序问题,一个线程必须等待另一个线程执行完某些任务后才能开始执行,而互斥则只是对资源的互斥访问,但是谁先谁后没有区别。

      关键段CRITICAL_SECTION,互斥量Mutex只能实现资源互斥,不能实现线程同步问题,如果线程之间有同步的关系,则需要使用Event和Semahore来实现,而后两者也可以实现互斥,同时解决同步。Event是相对简单,且使用较多,现在使用关键段和事件解决以下问题:

      主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。

该问题是在http://blog.csdn.net/morewindows/article/details/7442333中看到的问题,讲解也挺好,我自己实现了一下:

#include <iostream>
#include <Windows.h>
using namespace std;

const int THREADNUM = 10;
HANDLE threadHandles[THREADNUM];
int count = 0;
CRITICAL_SECTION cs; //控制count互斥访问
HANDLE hEvent;       //用事件控制传递的参数i的同步,主线程与子线程的同步

DWORD WINAPI threadProc(LPVOID lpParam);

int main()
{
    //初始化关键段区域
	InitializeCriticalSection(&cs);

	hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (hEvent == NULL)
	{
		cout << "创建事件对象错误" << endl;
		CloseHandle(hEvent);
	}

	for (int i = 0; i < THREADNUM; i++)
	{
		threadHandles[i] = CreateThread(NULL, 0, threadProc, (LPVOID)i, 0, NULL);
		if (threadHandles[i] == NULL)  //创建失败返回值是NULL
		{
			cout << "线程创建错误!" << endl;
		}
		WaitForSingleObject(hEvent, INFINITE);  //等待子线程参数传递和打印完成在执行下一个循环
	}

	WaitForMultipleObjects(THREADNUM, threadHandles, TRUE, INFINITE);
	for (int i = 0; i < THREADNUM; i++)
	{
		CloseHandle(threadHandles[i]);
	}
	CloseHandle(hEvent);
	system("pause");
	return 0;
}

DWORD WINAPI threadProc(LPVOID lpParam)
{
	int id = (int)lpParam;
	Sleep(50);
	EnterCriticalSection(&cs);
	count++;
	Sleep(0);
	cout << "线程序号:" << id << " count值为:" << count << endl;
	SetEvent(hEvent);  //子线程使用完参数后,设置事件为通知状态,主线程可以执行++操作
	LeaveCriticalSection(&cs);
    return 0;
}


运行结果如下“


以上看出,线程的序号正序输出,count值也按顺序打印。

总结:关键段实现了全局变量count的互斥使用,event实现了主线程与子线程参数传递和打印之间的同步


以下是信号量实现方式:

#include <iostream>
#include <Windows.h>
using namespace std;

const int THREADNUM = 10;
HANDLE threadHandles[THREADNUM];
int count = 0;
CRITICAL_SECTION cs; //控制count互斥访问
HANDLE hSemaphore;   //用信号量实现主线程与子线程的同步

DWORD WINAPI threadProc(LPVOID lpParam);

int main()
{
	//初始化关键段区域
	InitializeCriticalSection(&cs);

	hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
	if (hSemaphore == NULL)
	{
		cout << "创建事件对象错误" << endl;
		CloseHandle(hSemaphore);
	}

	for (int i = 0; i < THREADNUM; i++)
	{
		threadHandles[i] = CreateThread(NULL, 0, threadProc, (LPVOID)i, 0, NULL);
		if (threadHandles[i] == NULL)  //创建失败返回值是NULL
		{
			cout << "线程创建错误!" << endl;
		}
		WaitForSingleObject(hSemaphore, INFINITE);   //等待可用信号量,先挂起,等待线程运行完
	}

	WaitForMultipleObjects(THREADNUM, threadHandles, TRUE, INFINITE);
	for (int i = 0; i < THREADNUM; i++)
	{
		CloseHandle(threadHandles[i]);
	}
	CloseHandle(hSemaphore);
	system("pause");
	return 0;
}

DWORD WINAPI threadProc(LPVOID lpParam)
{
	int id = (int)lpParam;
	Sleep(50);
	EnterCriticalSection(&cs);
	count++;
	Sleep(0);
	cout << "线程序号:" << id << " count值为:" << count << endl;
	LeaveCriticalSection(&cs);
	ReleaseSemaphore(hSemaphore, 1, NULL);  //子线程使用完参数后,释放信号量,
	return 0;
}


运行结果和上面一样,发现代码基本相同,只是将相对应事件地方换成了信号量。相对应的函数不同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值