Windows线程间的同步

实验一

一、实验内容或题目:

在老师给的代码基础上,按照课本3.6.3的代码意图,实现一个生产者和一个消费者的同步问题。

二、实验目的与要求:

上传的producer-consumer.c已经编写了生产者和消费者线程的基础工作内容。请将之更改成多线程完成工作的方式,使两个线程可以正确的同步“生产-消费”行为。

三、实验步骤:

根据示例代码,实现两个进程向队列添加和取出的同步操作。
需要使用的api:_beginthread, CreateEvent, WaitForSingleObject, SetEvent。

四、实验结果:

在这里插入图片描述
达到了预期效果,消费者进程和生产者进程实现同步,程序持续运行。

五、总结:

Windows有四种同步同步方式,分别是临界区、事件、信号量、互斥量。该实验中使用的是设置事件的方式,首先说明一下所需要用到的api。_beginthread:创建线程;CreateEvent:创建一个事件;SetEvent:将事件变为有信号可使用状态;ResetEvent:将事件信号进行复位,变为无信号;WaitForSingleObject:等待,直到事件变为有信号状态,如果使用了一个事件,而不对它有任何操作,那么该进程将一直无法运行,因为一个事件默认是无信号状态,该api会使该进程一直等下去,当有信号时函数便会放行,无信号时,此函数将会一直阻塞。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由与示例代码稍微有一些复杂,所以我先改写了一下代码,简单说明这些api的使用。首先设一个全局变量为a,生产者进程就是每次在循环中执行a++,消费者进程就是每次在循环中执行a–,两个的退出循环条件都是当a等于0时退出,实现目标就是保证生产者进程在消费者进程之前执行,也就是实现同步。首先在main中创建一个事件hFull,在消费者进程增加一个判断,当a==1时执行WaitForSingleObject,等待hFull,由于hFull默认无信号(CreateEvent第三个参数为false),所以函数会一直等下去,直到生产者进程执行了SetEvent,将hull信号变为有信号,WaitForSingleObject才会执行接下来的代码,这样也就保证了生产者和消费者一直持续运行。如果不在生产者进程中写SetEvent,那么消费者会不在执行,一直等待。
关于CreateEvent的参数,其中当第二个参数为true时,表示其在WaitForSingleObject后必须手动调用ResetEvent清除信号,如果为false,表示其在WaitForSingleObject后系统自动清除事件信号;第三个参数为false,表示初始都为无信号状态;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
经过上面简单代码的分析,那么示例代码很容易看懂了,说明一下示例代码的逻辑,当队列为空时,在进入消费者进程中,会发动对hFull的WaitForSingleObject那么消费者进程将会被挂起,不在执行。在进入生产者进程后由于needWake为空,所以会对hFull发动SetEvent,此时队列已经添加进了元素,同时hFull也被赋予了信号,消费者进程又可以正常执行。队列满时同理。

实验二

一、实验内容或题目:

在实验一的基础上,按照课本3.6.4的代码意图,实现多个生产者和多个消费者的同步问题。

二、实验目的与要求:

实现多生产和多消费者之间的正确同步

三、实验步骤:

利用示例代码,改写变为多生产和多消费者之间的同步。
需要使用的api:CreateMutex, ReleaseMutex。

四、实验结果:

在这里插入图片描述
通过利用互斥量成功实现多个生产者和多个消费者的同步问题。

五、总结

如果单纯在实验一代码的基础上多添加连两个线程,可以发现两个生产者同时向0各自添加了产品,这显然是错误的。为了避免两个生产者或两个消费者同时操作列表,需要引入互斥量。采用互斥对象的机制,这样使得只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。
在这里插入图片描述
在这里插入图片描述
首先通过CreateMutex分别为生产者和消费者创建两个互斥量。在每次循环的第一句对hMutex执行WaitForSingleObject,这样就使得两个生产者或两个消费者不同时执行,在循环的最后用ReleaseMutex释放互斥量,使得等待的另一个生产者或消费者可以开始执行,这样就实现多个生产者和多个消费者的同步问题。
在这里插入图片描述
在这里插入图片描述

附录

multi.cpp

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h> 
#include <process.h>
#include <math.h>
#include <time.h>

#define POOL_SIZE	10

unsigned int Pool[POOL_SIZE];
unsigned int PoolHeader = 0;
unsigned int PoolTail = 0;

#define POOL_FULL	(((PoolHeader + 1) % POOL_SIZE) == PoolTail)
#define POOL_EMPTY	(PoolHeader == PoolTail)

HANDLE hEmpty;
HANDLE hFull;
HANDLE hMutex_producer;	//定义互斥对象句柄
HANDLE hMutex_consumer;

/**
生产者线程
**/
unsigned __stdcall producer(void* pArguments) {
    
    
	const unsigned int threadId = GetCurrentThreadId();
	do {
    
    
		WaitForSingleObject(hMutex_producer, INFINITE);
		if (!POOL_FULL) {
    
    
			printf("生产者【%d】向【%d】格子里添加了一个产品\n", threadId, PoolHeader);
			Pool[PoolHeader] = 1;
			BOOL needWake = POOL_EMPTY;
			PoolHeader = (PoolHeader + 1) % POOL_SIZE;
			if (needWake) {
    
    
				SetEvent(hFull);
			}
		}
		else {
    
    
			printf("生产者【%d】开始等待\n", threadId);
			WaitForSingleObject(hEmpty, INFINITE);
		}
		const unsigned int rest = rand() % 2000;
		Sleep(rest);
		ReleaseMutex(hMutex_producer);
	} while (TRUE);
}

/**
消费者线程
**/
unsigned __stdcall consumer(void* pArguments) {
    
    
	const unsigned int threadId = GetCurrentThreadId();
	do {
    
    
		WaitForSingleObject(hMutex_consumer, INFINITE);
		if (!POOL_EMPTY) {
    
    
			printf("消费者【%d】从【%d】格子里取走了一个产品\n", threadId, PoolTail);
			Pool[PoolTail] = 1;
			BOOL needWake = POOL_FULL;
			PoolTail = (PoolTail + 1) % POOL_SIZE;

			if (needWake) {
    
    
				SetEvent(hEmpty);
			}
		}
		else {
    
    
			printf("消费者【%d】开始等待\n", threadId);
			WaitForSingleObject(hFull, INFINITE);
		}
		const unsigned int rest = rand() % 2000;
		Sleep(rest);
		ReleaseMutex(hMutex_consumer);
	} while (TRUE);
}

int main() {
    
    
	// 创建事件
	hEmpty = CreateEvent(
		NULL,               // default security attributes
		TRUE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("WriteEvent")  // object name
	);
	// 判断是否创建成功
	if (hEmpty == NULL)
	{
    
    
		printf("CreateEvent failed (%d)\n", GetLastError());
		return 0;
	}
	hFull = CreateEvent(
		NULL,               // default security attributes
		TRUE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("WriteEvent")  // object name
	);
	if (hFull == NULL)
	{
    
    
		printf("CreateEvent failed (%d)\n", GetLastError());
		return 0;
	}
	// 创建互斥量
	hMutex_producer = CreateMutex(NULL, false, NULL);
	hMutex_consumer = CreateMutex(NULL, false, NULL);
	// 设定随机数种子
	srand((unsigned int)time(NULL));
	//创建进程
	HANDLE hThreads[4];
	hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, &producer, NULL, 0, NULL);
	hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, &consumer, NULL, 0, NULL);

	hThreads[2] = (HANDLE)_beginthreadex(NULL, 0, &producer, NULL, 0, NULL);
	hThreads[3] = (HANDLE)_beginthreadex(NULL, 0, &consumer, NULL, 0, NULL);
	// 无线等待进程结束
	WaitForMultipleObjects(4, hThreads, TRUE, INFINITE);

	CloseHandle(hThreads);
	CloseHandle(hFull);
	CloseHandle(hEmpty);
	CloseHandle(hMutex_producer);
	CloseHandle(hMutex_consumer);
	return 0;
}

simple_example.cpp

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h> 
#include <process.h>
#include <math.h>
#include <time.h>

#define POOL_SIZE	10

unsigned int Pool[POOL_SIZE];
unsigned int PoolHeader = 0;
unsigned int PoolTail = 0;

#define POOL_FULL	(((PoolHeader + 1) % POOL_SIZE) == PoolTail)
#define POOL_EMPTY	(PoolHeader == PoolTail)

HANDLE hEmpty;
HANDLE hFull;

int a = 1;

/**
生产者线程
**/
unsigned  __stdcall producer(void* pArguments) {
    
    
	const unsigned int threadId = GetCurrentThreadId();
	do {
    
    
		a++;
		printf("生产者%d\n", a);
		SetEvent(hFull);
		const unsigned int rest = rand() % 2000;
		Sleep(rest);
	} while (a != 0);
	return 0;
}

/**
消费者线程
**/
unsigned  __stdcall consumer(void* pArguments) {
    
    
	const unsigned int threadId = GetCurrentThreadId();
	do {
    
    
		if (a == 1)
		{
    
    
			printf("在等了");
			WaitForSingleObject(hFull, INFINITE);
		}
		a--;
		printf("消费者%d\n", a);
		const unsigned int rest = rand() % 2000;
		Sleep(rest);
	} while (a != 0);
	return 0;
}

void main() {
    
    
	hFull = CreateEvent(
		NULL,               // default security attributes
		FALSE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("WriteEvent_two")  // object name
	);
	if (hFull == NULL)
	{
    
    
		printf("CreateEvent failed (%d)\n", GetLastError());
		return;
	}
	// 设定随机数种子
	srand((unsigned int)time(NULL));
	//创建进程
	HANDLE hThreads[2];
	hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, &producer, NULL, 0, NULL);
	hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, &consumer, NULL, 0, NULL);
	// 无线等待进程结束
	WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);

	CloseHandle(hThreads[0]);
	CloseHandle(hThreads[1]);
	CloseHandle(hFull);
}

single.cpp

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h> 
#include <process.h>
#include <math.h>
#include <time.h>

#define POOL_SIZE	10

unsigned int Pool[POOL_SIZE];
unsigned int PoolHeader = 0;
unsigned int PoolTail = 0;

#define POOL_FULL	(((PoolHeader + 1) % POOL_SIZE) == PoolTail)
#define POOL_EMPTY	(PoolHeader == PoolTail)

HANDLE hEmpty;
HANDLE hFull;

/**
生产者线程
**/
unsigned __stdcall producer(void* pArguments) {
    
    
	const unsigned int threadId = GetCurrentThreadId();
	do {
    
    
		if (!POOL_FULL) {
    
    
			printf("生产者【%d】向【%d】格子里添加了一个产品\n", threadId, PoolHeader);
			Pool[PoolHeader] = 1;
			BOOL needWake = POOL_EMPTY;
			PoolHeader = (PoolHeader + 1) % POOL_SIZE;
			if (needWake) {
    
    
				SetEvent(hFull);
			}
		}
		else {
    
    
			printf("生产者【%d】开始等待\n", threadId);
			WaitForSingleObject(hEmpty, INFINITE);
		}
		const unsigned int rest = rand() % 2000;
		Sleep(rest);
	} while (TRUE);
}

/**
消费者线程
**/
unsigned __stdcall consumer(void* pArguments) {
    
    
	const unsigned int threadId = GetCurrentThreadId();
	do {
    
    
		if (!POOL_EMPTY) {
    
    
			printf("消费者【%d】从【%d】格子里取走了一个产品\n", threadId, PoolTail);
			Pool[PoolTail] = 1;
			BOOL needWake = POOL_FULL;
			PoolTail = (PoolTail + 1) % POOL_SIZE;
			if (needWake) {
    
    
				SetEvent(hEmpty);
			}
		}
		else {
    
    
			printf("消费者【%d】开始等待\n", threadId);
			WaitForSingleObject(hFull, INFINITE);
		}

		const unsigned int rest = rand() % 2000;
		Sleep(rest);
	} while (TRUE);
}

int main() {
    
    
	// 创建事件
	hEmpty = CreateEvent(
		NULL,               // default security attributes
		TRUE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("WriteEvent")  // object name
	);
	// 判断是否创建成功
	if (hEmpty == NULL)
	{
    
    
		printf("CreateEvent failed (%d)\n", GetLastError());
		return 0;
	}
	hFull = CreateEvent(
		NULL,               // default security attributes
		TRUE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("WriteEvent")  // object name
	);
	if (hFull == NULL)
	{
    
    
		printf("CreateEvent failed (%d)\n", GetLastError());
		return 0;
	}
	// 设定随机数种子
	srand((unsigned int)time(NULL));
	//创建进程
	HANDLE hThreads[2];
	hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, &producer, NULL, 0, NULL);
	hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, &consumer, NULL, 0, NULL);
	// 无线等待进程结束
	WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
	CloseHandle(hThreads[0]);
	CloseHandle(hThreads[1]);
	CloseHandle(hFull);
	CloseHandle(hEmpty);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Fishermen_sail/article/details/129886663