双线程读写队列数据

MFC对话框中一个按钮的响应函数实现两个功能:
显示数据同时处理数据,因此开两个线程,一个线程显示数据(开了一个定时器,响应WM_TIMER消息按照一定时间间隔向TeeChart图表添加数据并显示)同时在队列队尾添加数据,另一个线程从该队列队头去数据来处理。


下面就来解决这个案例。先来分析下:

这个案例是一个线程向队列中的队列头部读取数据,一个线程向队列中的队列尾部写入数据。看起来很像读者写者问题,但其实不然,如果将队列看成缓冲区,这个案例明显是个生产者消费者问题。因此我们仿照生产者消费者的思路来具体分析下案例中的“等待”情况:

    1.     当队列为空时,读取数据线程必须等待写入数据向队列中写入数据。也就是说当队列为空时,读取数据线程要等待队列中有数据。

    2.     当队列满时,写入数据线程必须等待读取数据线程向队列中读取数据。也就是说当队列满时,写入数据线程要等待队列中有空位。

在访问队列时,需要互斥吗?这将依赖于队列的数据结构实现,如果使用STL中的vector,由于vector会动态增长。因此要做互斥保护。如果使用循环队列,那么读取数据线程拥有读取指针,写入数据线程拥有写入指针,各自将访问队列中不同位置上的数据,因此不用进行互斥保护。

分析完毕后,再来考虑使用什么样的数据结构。使用两个信号量,一个来记录循环队列中空位的个数,一个来记录循环队列中产品的个数(非空位个数)。

代码非常容易写出,下面给出完整的源代码。
 

#include <stdio.h>  
#include <process.h>  
#include <windows.h>  
#include <time.h>  
 
#include<iostream>
#include<iomanip>
using namespace std;
 
const int iQueue = 5;
int arrQueue[iQueue];
 
int iRead, iWrite, iCnt;
//关键段
CRITICAL_SECTION csConsole;//互斥访问控制台
//信号量
HANDLE hSemaphoreQueueEmpty;//表示队列中空位
HANDLE hSemaphoreQueueFull;//表示队列中数据
 
 
//设置控制台输出颜色  
//SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
 
 
//读数据线程函数
UINT WINAPI ReaderProc(PVOID pParam){
	int iData = 0;
	while(iData < 20){
		//等待数据
		WaitForSingleObject(hSemaphoreQueueFull, INFINITE);
		iData = arrQueue[iRead];
		iRead = (iRead+1)%iQueue;
		EnterCriticalSection(&csConsole);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);  
		cout << "从队列中读数据" << iData << endl;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
		LeaveCriticalSection(&csConsole);
		Sleep(rand() % 100);
		//空闲位+1
		ReleaseSemaphore(hSemaphoreQueueEmpty, 1, NULL);
	}
	return 0;
}
 
//写数据线程函数  
UINT WINAPI WriterProc(PVOID pParam){
	int iData = 0;
	while(iData < 20){
		//等待队列中数据
		WaitForSingleObject(hSemaphoreQueueEmpty, INFINITE);
		arrQueue[iWrite] = ++iData;
		iWrite = (iWrite+1)%iQueue;
		EnterCriticalSection(&csConsole);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);  
		cout << "将数据" << iData << "写入队列" << endl;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
		LeaveCriticalSection(&csConsole);
		Sleep(rand()%100);
		//数据位+1
		ReleaseSemaphore(hSemaphoreQueueFull, 1, NULL);
	}
	return 0;
}
 
//双线程读写队列数据
void TrTw()
{
	//初始化关键段
	InitializeCriticalSection(&csConsole);
	//空闲位信号量:初始全为空闲
	hSemaphoreQueueEmpty = CreateSemaphore(NULL, iQueue, iQueue, NULL);
	//数据位信号量:初始没有数据
	hSemaphoreQueueFull = CreateSemaphore(NULL, 0, iQueue, NULL);
 
	srand(time(NULL));
	iRead = iWrite = 0;
	memset(arrQueue, 0, sizeof(int)*iQueue);
	HANDLE hThreads[2];
	hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, ReaderProc, NULL, 0, NULL);
	hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, WriterProc, NULL, 0, NULL);
	WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
	for(int i = 0; i < 2; i++)			CloseHandle(hThreads[i]);
 
	//销毁关键段和信号量
	DeleteCriticalSection(&csConsole);
	CloseHandle(hSemaphoreQueueEmpty);
	CloseHandle(hSemaphoreQueueFull);
}

猜你喜欢

转载自blog.csdn.net/CherishPrecious/article/details/83817937