线程同步的四种方式(一)

并发concurent与并行parallel的区别:
在这里插入图片描述

  1. 互斥对象
    首先我们需要创建CreateMutex一把互斥对象,我们可以指明当前线程是否拥有它,互斥对象完全就像一把钥匙一样,我们用WaitForSignalObject来等待这把钥匙,但是这把钥匙被等到并且使用后必须释放-----ReleaseMutex ,不然别人永远无法等到。这样从等待到释放中间的代码段永远都是只有一个线程在执行,也就形成了互斥控制。当然互斥对象的句柄是要关闭的CloseHandle
#include<windows.h>
#include<iostream>
using namespace std;

int ticket = 100;
HANDLE hMutex; //定义互斥对象

DWORD WINAPI FuncProc1(LPVOID lpParameter);
DWORD WINAPI FuncProc2(LPVOID lpParameter);


int main()
{	
	hMutex = CreateMutex(NULL, FALSE, NULL); //定义互斥对象,并让该线程不拥有它
	HANDLE hThread1 = CreateThread(NULL, 0, FuncProc1, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL,0, FuncProc2, NULL, 0, NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	Sleep(1000); //让主线程睡眠1秒	 
	return 0;
}

DWORD WINAPI FuncProc1(LPVOID lpParameter) {
	while (true) {
		WaitForSingleObject(hMutex, INFINITE);
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket1 :" << ticket-- << endl;
		}
		else
			break;
		ReleaseMutex(hMutex);
	}
	return 0;
}

DWORD WINAPI FuncProc2(LPVOID lpParameter) {
	while (true) {
		WaitForSingleObject(hMutex, INFINITE); //申请互斥对象的所有权
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket2 :" << ticket-- << endl;
		}
		else
			break;
		ReleaseMutex(hMutex); //释放互斥对象的所有权
	}
	return 0;
}

注意:

虽然改程序运行结果是某一条线程执行完然后第二条线程执行,如此往复,但是这不是同步,因为我们没法控制到底一开始是谁先执行,(我们只是控制了轮流次序)。

  1. 事件
    首先我们需要创建CreateEvent一个事件对象,它的使用方式是触发方式,要想被WaitForSingleObject等待到该事件对象必须是有信号的,事件要想有信号可以用SetEvent手动置为有信号,要想事件对象无信号可以使用ResetEvent(或者在创建事件对象时就声明),该事件对象在WaitForSingleObject后自动置为无信号,见上面CreateEvent第二个参数),打个小小比方,手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。当然事件对象的句柄是要关闭的CloseHandle。

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

int ticket = 100;
HANDLE g_hEvent;

DWORD WINAPI FuncProc1(LPVOID lpParameter);
DWORD WINAPI FuncProc2(LPVOID lpParameter);


int main()
{	
	//参数意义:默认安全性,自动重置事件,初始时该事件对象就有信号
	g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
	HANDLE hThread1 = CreateThread(NULL, 0, FuncProc1, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL,0, FuncProc2, NULL, 0, NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	Sleep(1000); //让主线程睡眠1秒	 
	CloseHandle(g_hEvent);
	return 0;
}

DWORD WINAPI FuncProc1(LPVOID lpParameter) {
	while (true) {
		WaitForSingleObject(g_hEvent, INFINITE); //申请事件对象(申请钥匙,持有钥匙)
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket1 :" << ticket-- << endl;
			SetEvent(g_hEvent); //(放弃钥匙,不在拥有)
		}
		else
		{
			SetEvent(g_hEvent); //设置为有信号
			break;
		}
	}
	return 0;
}

DWORD WINAPI FuncProc2(LPVOID lpParameter) {
	while (true) {
		WaitForSingleObject(g_hEvent, INFINITE); //申请事件对象(申请钥匙,持有钥匙)
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket2 :" << ticket-- << endl;
			SetEvent(g_hEvent); //(放弃钥匙,不在拥有)
		}
		else
		{
			SetEvent(g_hEvent); //设置为有信号
			break;
		}
	}
	return 0;
}

改进:具有严格的同步控制

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

int ticket = 100;
HANDLE g_hEvent1;
HANDLE g_hEvent2;

DWORD WINAPI FuncProc1(LPVOID lpParameter);
DWORD WINAPI FuncProc2(LPVOID lpParameter);


int main()
{	
	g_hEvent1 = CreateEvent(NULL, FALSE, TRUE, NULL); //创建事件对象
	g_hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL); //创建事件对象
	HANDLE hThread1 = CreateThread(NULL, 0, FuncProc1, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL,0, FuncProc2, NULL, 0, NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	Sleep(1000); //让主线程睡眠1秒	 
	CloseHandle(g_hEvent1);
	CloseHandle(g_hEvent2);
	return 0;
}

DWORD WINAPI FuncProc1(LPVOID lpParameter) {
	while (true) {
		WaitForSingleObject(g_hEvent1, INFINITE); //申请事件对象(申请钥匙,持有钥匙)
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket1 :" << ticket-- << endl;
			SetEvent(g_hEvent2); //让线程2执行
		}
		else
		{
			SetEvent(g_hEvent2); //让线程2执行
			break;
		}
	}
	return 0;
}

DWORD WINAPI FuncProc2(LPVOID lpParameter) {
	while (true) {
		WaitForSingleObject(g_hEvent2, INFINITE); //申请事件对象(申请钥匙,持有钥匙)
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket2 :" << ticket-- << endl;
			SetEvent(g_hEvent1); //让线程1执行
		}
		else
		{
			SetEvent(g_hEvent1); //让线程1执行
			break;
		}
	}
	return 0;
}
  1. 临界区
#include<iostream>
#include "windows.h"
using namespace std;

DWORD WINAPI FunProc1(LPVOID lpParameter);
DWORD WINAPI FunProc2(LPVOID lpParameter);

int ticket = 1000;

CRITICAL_SECTION g_cs;

int main()
{
	InitializeCriticalSection(&g_cs);  //初始化临界区
	HANDLE hThread1 = CreateThread(NULL, 0, FunProc1, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, FunProc2, NULL, 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	Sleep(1000);
	DeleteCriticalSection(&g_cs); //删除临界区
	return 0;
}


DWORD WINAPI FunProc1(LPVOID lpParameter)
{
	while (TRUE) {
		EnterCriticalSection(&g_cs); //进入临界区
		Sleep(1);
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket1: " << ticket-- << endl;
			LeaveCriticalSection(&g_cs); //离开临界区
		}
		else {
			LeaveCriticalSection(&g_cs); //离开
			break; 
		}
	}
	return 0;
}

DWORD WINAPI FunProc2(LPVOID lpParameter)
{
	while (TRUE) {
		EnterCriticalSection(&g_cs);
		Sleep(1);
		if (ticket > 0) {
			Sleep(1);
			cout << "ticket2: " << ticket-- << endl;
			LeaveCriticalSection(&g_cs);
		}
		else {
			LeaveCriticalSection(&g_cs);
			break;
		}
	}
	return 0;
}


https://blog.csdn.net/ebowtang/article/details/29905309

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值