认识死锁之生产者与消费者

上一篇博文:

https://blog.csdn.net/qq78442761/article/details/81276366

这里有一点:

CRITICAL_SECTION

此玩意,类似于互斥锁,是Windows平台提供的。

程序运行截图如下:

源码如下:

DeadLock.h

#pragma once

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

#define PRODUCERCNT 1	//生产者线程数量
#define CONSUMERCNT 1	//消费者线程数量
#define TOTALCNT PRODUCERCNT+CONSUMERCNT

class CDeadLock
{
public:
	CDeadLock();
	~CDeadLock();

	void CreateThread();
	void ToggleStatus();

private:
	HANDLE hConsole;	//控制台句柄-改变控制台颜色输出
	bool m_bRunning;	//通知线程需要关闭
	int m_buffer;	//关键数据-临界资源
	HANDLE threads[TOTALCNT];	//保存所有线程句柄
	static DWORD WINAPI producer(LPARAM lParam);	//生产者线程函数
	static DWORD WINAPI consumer(LPARAM lParam);	//消费者线程函数

	//生产和消费动作
	void produce();
	void consume();

	//Windows中提供了关键段,来协调
	CRITICAL_SECTION m_cs;
};

DeadLock.cpp

#include "DeadLock.h"



CDeadLock::CDeadLock()
{
	hConsole = INVALID_HANDLE_VALUE;
	m_bRunning = false;
	m_buffer = 0;
	for (int i = 0; i < TOTALCNT; i++) {
		threads[i] = INVALID_HANDLE_VALUE;
	}

	hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTitle(L"死锁");
	
	InitializeCriticalSection(&m_cs);
}


CDeadLock::~CDeadLock()
{
	CloseHandle(hConsole);
	for (int i = 0; i < TOTALCNT; i++) {
		if (threads[i] != INVALID_HANDLE_VALUE) {
			CloseHandle(threads[i]);
		}
	}

	DeleteCriticalSection(&m_cs);
}

void CDeadLock::CreateThread()
{
	int i = 0;
	m_bRunning = true;
	for (; i < PRODUCERCNT; i++) {
		threads[i] = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)producer, this, 0, 0);
	}
	for (i = 0; i < CONSUMERCNT; i++) {
		threads[i] = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)consumer, this, 0, 0);
	}
}

void CDeadLock::ToggleStatus()
{
	m_bRunning = !m_bRunning;
}

//生产者线程
DWORD WINAPI CDeadLock::producer(LPARAM lParam)
{
	CDeadLock *pThis = (CDeadLock*)lParam;
	cout << "producer threadID:" << GetCurrentThreadId() << endl;
	while (pThis->m_bRunning) {
		EnterCriticalSection(&pThis->m_cs);
		SetConsoleTextAttribute(pThis->hConsole, FOREGROUND_RED);
		pThis->produce();
		LeaveCriticalSection(&pThis->m_cs);
	}
	return 0;
}

//消费者线程
DWORD WINAPI CDeadLock::consumer(LPARAM lParam)
{
	CDeadLock *pThis = (CDeadLock*)lParam;
	cout << "consumer threadID:" << GetCurrentThreadId() << endl;
	while (pThis->m_bRunning) {
		Sleep(10);
		EnterCriticalSection(&pThis->m_cs);
		SetConsoleTextAttribute(pThis->hConsole, FOREGROUND_GREEN);
		pThis->consume();
		LeaveCriticalSection(&pThis->m_cs);
	}
	return 0;
}

void CDeadLock::produce()
{
	if (m_buffer > 200) {
		return;
	}
	//m_buffer++;
	__asm {
		mov         eax, dword ptr[this]	//取this指针
		mov         ecx, dword ptr[eax + 8]	//取m_buffer的值,放在ecx寄存器里面

		//有可能执行到这一步,发送时间片到期的状态...	如果是10,那么这个10已经到了ecx寄存器里面,
		//这时候,消费者开始消耗了,消费者消耗完后应该是9,
		//但是,这个时候生产者的时间片又到了,此时把寄存器++,变成了11,这样就有问题了!!!
		add         ecx, 1					//ECX++
		mov         edx, dword ptr[this]	//取this指针
		//此处可以直接这么优化 mov dword prt[eax+8],ecx
		mov         dword ptr[edx + 8], ecx	//再放回去
	}
	printf("生产 - %d\n", m_buffer);
}


void CDeadLock::consume()
{
	int data = m_buffer--;
	if (data) {
		printf("消费 - %d\n", data);
	}
}

main.cpp

#include "DeadLock.h"
#include <conio.h>

void main() {

	cout << "main called!\n";
	CDeadLock deadLock;
	deadLock.CreateThread();	//注意,如果CreateThread两次,那么以前的线程就会被抛弃掉
	cout << "press any key to exit ... \n";
	while (true) {
		char cmd = _getch();
		if (cmd == 'q') {
			break;
		}
		else if (cmd == 'n') {
			deadLock.ToggleStatus();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq78442761/article/details/81293940