临界区、事件、互斥量、 信号量--四种控制多线程同步与互斥的方法

// MultiThread.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

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

CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;

UINT WINAPI PrintThread1(LPVOID lp)
{
	while (1)
	{
		//该代码段最后看,用信号量实现10个线程同步有序
		//if (WaitForSingleObject(g_hDemaphore, INFINITE) != WAIT_OBJECT_0)
		//{
			//continue;
		//}
		//
		EnterCriticalSection(&g_csA);
		for (int i=0;i<3;i++)
		{
			printf("thread1\n");
			Sleep(1000);
		}
		printf("\n");
		LeaveCriticalSection(&g_csA);
	}

	return 0;
}

UINT WINAPI PrintThread2(LPVOID lp)
{
	while (1)
	{
		EnterCriticalSection(&g_csA);
		for (int i=0;i<3;i++)
		{
			printf("thread2\n");
			Sleep(100);
		}
		printf("\n");
		LeaveCriticalSection(&g_csA);
	}

	return 0;
}
///
HANDLE g_hEvent;
UINT WINAPI PrintThread3(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hEvent, INFINITE);
		if (dwResult == WAIT_OBJECT_0)
		{
			for (int i=0;i<3;i++)
			{
				printf("thread3\n");
				Sleep(500);
			}
			printf("\n");
		}
		SetEvent(g_hEvent);
	}

	return 0;
}

UINT WINAPI PrintThread4(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hEvent, INFINITE);
		if (dwResult == WAIT_OBJECT_0)
		{
			for (int i=0;i<3;i++)
			{
				printf("thread4\n");
				Sleep(300);
			}
			printf("\n");
		}
		SetEvent(g_hEvent);
	}

	return 0;
}

///
HANDLE g_hMutex;
UINT WINAPI PrintThread5(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hMutex, 500);//当前线程拥有该互斥量
		if (dwResult == WAIT_OBJECT_0)
		{
			for (int i=0;i<3;i++)
			{
				printf("thread5\n");
				Sleep(200);
			}
			printf("\n");
		}
		if (!ReleaseMutex(g_hMutex))//当前线程释放该互斥量
		{
			DWORD dwError = GetLastError();
			if (dwError == ERROR_NOT_OWNER)
			{
				printf("thread5 error:ERROR_NOT_OWNER\n");
			}
			else
			{
				printf("thread5 error:%d\n", dwError);
			}
		}
	}

	return 0;
}

UINT WINAPI PrintThread6(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hMutex, 1000);
		if (dwResult == WAIT_OBJECT_0)
		{
			for (int i=0;i<3;i++)
			{
				printf("thread6\n");
				Sleep(400);
			}
			printf("\n");
		}
		if (!ReleaseMutex(g_hMutex)) //如果互斥量被线程5占有,那么当前线程将无法释放,只有占有者可以释放
		{
			DWORD dwError = GetLastError();
			if (dwError == ERROR_NOT_OWNER)
			{
				printf("thread6 error:ERROR_NOT_OWNER\n");
			}
			else
			{
				printf("thread6 error:%d\n", dwError);
			}
		}
	}

	return 0;
}
//
HANDLE g_hDemaphore;
UINT WINAPI PrintThread7(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hDemaphore, INFINITE);//占用一个资源计数
		if (dwResult == WAIT_OBJECT_0)
		{
			printf("Anglela");
			Sleep(1000);
		}

		LONG count;
		ReleaseSemaphore(g_hDemaphore,1,&count);//释放一个资源计数
	}

	return 0;
}

UINT WINAPI PrintThread8(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hDemaphore, INFINITE);//减少一个资源计数(如果还有资源计数)
		if (dwResult == WAIT_OBJECT_0)
		{
			printf("Baby\n");
			printf("\n");
			Sleep(1000);
		}

		LONG count;
		ReleaseSemaphore(g_hDemaphore,1,&count);//增加一个资源计数

		Sleep(2000);// 减少后并不立即增加
	}

	return 0;
}

UINT WINAPI PrintThread9(LPVOID lp)
{
	while (1)
	{
		DWORD dwResult = WaitForSingleObject(g_hDemaphore, INFINITE);
		Sleep(1000);
		if (dwResult == WAIT_OBJECT_0)
		{
			printf("Alice ");
			Sleep(500);
		}

		LONG count;
		BOOL bFlag = ReleaseSemaphore(g_hDemaphore,3,&count);
		if (!bFlag)
		{
			printf("\n");
			printf("thread9 release failed:%d\n", GetLastError());
		}
	}

	return 0;
}

UINT WINAPI PrintThread10(LPVOID lp)
{
	DWORD dwResult = 0;
	while (1)
	{
		//减少2个资源计数
		dwResult = WaitForSingleObject(g_hDemaphore, INFINITE);
		dwResult = WaitForSingleObject(g_hDemaphore, INFINITE);
		if (dwResult == WAIT_OBJECT_0)
		{
			printf("in Wonderland\n");
			printf("\n");
			Sleep(1000);
		}

		::EnterCriticalSection(&g_csB);
		LONG count;// if rcount+pcount>maxcount,增加资源计数失败且当前资源计数不变
		BOOL bFlag = ReleaseSemaphore(g_hDemaphore,2/*relasecount*/,&count/*previous count*/);//增加2个资源计数
		if (!bFlag)
		{
			printf("\n");
			printf("thread10 release failed:%d\n", GetLastError());
		}
		printf("thread10 previous count:%d\n", count);//执行release以前的资源计数
		::LeaveCriticalSection(&g_csB);
	}

	return 0;
}

// 除了临界区,其他为内核对象,除了用于线程还可用于进程,可以通过创建时指定的名字打开夸进程使用
//
int _tmain(int argc, _TCHAR* argv[])
{
	InitializeCriticalSection(&g_csA);
	InitializeCriticalSection(&g_csB);

	HANDLE m_hThread = NULL;

	//同步与互斥:‘1个生产者-N个消费者’模型,同步有序-必须先生产然后消费,互斥无序,要么执行A,要么执行B,AB顺序未知
	//由于线程1比线程2先执行,临界区保证打印结果thread1,thread2有序
	//m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread1, NULL, 0, NULL);
	//m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread2, NULL, 0, NULL);

	//使用事件控制线程3,4有序执行
	//创建一个命名的自动重置事件内核对象,第二个参数FALSE指定自动重置,第三个参数TRUE设置初始化为有信号
	g_hEvent=CreateEvent(NULL,FALSE,TRUE,LPCWSTR("myevent"));
	if (g_hEvent)
	{
		if (ERROR_ALREADY_EXISTS==GetLastError())
		{
			printf("error:event alread exist\n");
		}
	}
	// 可以打开其他进程创建的事件对象
	//$ g_hEvent = OpenEventA(EVENT_ALL_ACCESS, TRUE, LPCWSTR("myevent"));
	//$ ResetEvent(g_hEvent);

	//m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread3, NULL, 0, NULL);
	//m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread4, NULL, 0, NULL);

	//第二个参数TRUE,main线程拥有互斥量,体现互斥量‘线程拥有’的概念,区别事件‘先到先得’
	g_hMutex = CreateMutexA(NULL, TRUE, "mymutex");
	//$ g_hMutex = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, "mymutex");

	/*m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread5, NULL, 0, NULL);
	m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread6, NULL, 0, NULL);
	//$ 事件对象设置为自动重置与互斥量有类似功能
	Sleep(3000);
	printf("main thread release mutex\n");
	printf("\n");
	ReleaseMutex(g_hMutex);*/

	// 信号量体现‘资源计数’的概念,通过修改初始计数与释放增加计算使打印有序
	// SEMAPHORE_MODIFY_STATE,初始资源计数为2时,信号量为有信号状态,最大允许资源计数为10时,信号量为有信号状态
	g_hDemaphore=CreateSemaphoreA(NULL,2,10,("Sem"));//初始资源计数为1,最大允许资源计数为2,通过release增加资源计数
	//$ HANDLE semaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, _T("Global\\TestSemaphore"));
	m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread7, NULL, 0, NULL);
	m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread8, NULL, 0, NULL);
	m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread9, NULL, 0, NULL);
	m_hThread =(HANDLE)_beginthreadex(NULL, 0, PrintThread10, NULL, 0, NULL);
	
	while (getchar()!='x')
	{
	}
	DeleteCriticalSection(&g_csA);
	DeleteCriticalSection(&g_csB);

	CloseHandle(m_hThread);

	CloseHandle(g_hEvent);

	if (WaitForSingleObject(g_hMutex, 0) == WAIT_ABANDONED)
	{
		ReleaseMutex(g_hMutex);
	}
	CloseHandle(g_hMutex);

	return 0;
}


1.线程1,2实现打印thread1,thread2有序,thread3~thread6实现类似打印功能;

2.线程7,8,9,10实现打印两个有序字符串,通过修改初始计数与增减计数实现打印有序;

3.MFC将4方法封装4个类功能相同,除了临界区,其他3个可以进程间使用。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值