秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据

来源:互联网 发布:淘宝知识产权侵权申诉 编辑:程序博客网 时间:2024/06/06 18:47

本文配套程序下载地址为:http://download.csdn.net/detail/morewindows/5136035

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8646902

欢迎关注微博:http://weibo.com/MoreWindows

 

在《秒杀多线程系列》的前十五篇中介绍多线程的相关概念,多线程同步互斥问题《秒杀多线程第四篇一个经典的多线程同步问题》及解决多线程同步互斥的常用方法——关键段事件互斥量信号量读写锁。为了让大家更加熟练运用多线程,将会有十篇文章来讲解十个多线程使用案例,相信看完这十篇后会让你能更加游刃有余的使用多线程。

首先来看第一篇——《秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据》

《多线程十大经典案例之一双线程读写队列数据》案例描述:

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

本案例来源于http://bbs.csdn.net/topics/390383114,感谢hehening88提供题目,特此鸣谢。

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

 

《多线程十大经典案例之一双线程读写队列数据》案例分析:

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

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

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

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

分析完毕后,再来考虑使用什么样的数据结构,同样依照《秒杀多线程第十篇生产者消费者问题》中的做法。使用两个信号量,一个来记录循环队列中空位的个数,一个来记录循环队列中产品的个数(非空位个数)。代码非常容易写出,下面给出完整的源代码。

代码中的信号量相关函数可以参考《秒杀多线程第八篇经典线程同步信号量Semaphore》,代码中的SetConsoleColor是用来改变控制台的文字颜色,具体可以参考《VC 控制台颜色设置》。

 

《多线程十大经典案例之一双线程读写队列数据》完整代码:

//秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据//http://blog.csdn.net/MoreWindows/article/details/8646902#include <stdio.h>#include <process.h>#include <windows.h>#include <time.h>const int QUEUE_LEN = 5;int g_arrDataQueue[QUEUE_LEN];int g_i, g_j, g_nDataNum;//关键段 用于保证互斥的在屏幕上输出CRITICAL_SECTION g_cs;//信号量 g_hEmpty表示队列中空位 g_hFull表示队列中非空位HANDLE     g_hEmpty, g_hFull;//设置控制台输出颜色BOOL SetConsoleColor(WORD wAttributes){HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);if (hConsole == INVALID_HANDLE_VALUE)return FALSE;return SetConsoleTextAttribute(hConsole, wAttributes);}//读数据线程函数unsigned int __stdcall ReaderThreadFun(PVOID pM){int nData = 0;while (nData < 20){WaitForSingleObject(g_hFull, INFINITE);nData = g_arrDataQueue[g_i];g_i = (g_i + 1) % QUEUE_LEN;EnterCriticalSection(&g_cs);printf("从队列中读数据%d\n", nData);LeaveCriticalSection(&g_cs);Sleep(rand() % 300);ReleaseSemaphore(g_hEmpty, 1, NULL);}return 0;}//写数据线程函数unsigned int __stdcall WriterThreadFun(PVOID pM){int nData = 0;while (nData < 20){WaitForSingleObject(g_hEmpty, INFINITE);g_arrDataQueue[g_j] = ++nData;g_j = (g_j + 1) % QUEUE_LEN;EnterCriticalSection(&g_cs);SetConsoleColor(FOREGROUND_GREEN);printf("    将数据%d写入队列\n", nData);SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);LeaveCriticalSection(&g_cs);Sleep(rand() % 300);ReleaseSemaphore(g_hFull, 1, NULL);}return 0;}int main(){printf("     秒杀多线程第十六篇 多线程十大经典案例 双线程读写队列数据\n");printf(" - by MoreWindows( http://blog.csdn.net/MoreWindows/article/details/8646902 ) -\n\n");InitializeCriticalSection(&g_cs);g_hEmpty = CreateSemaphore(NULL, QUEUE_LEN, QUEUE_LEN, NULL);g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);srand(time(NULL));g_i = g_j = 0;HANDLE hThread[2];hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);hThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);WaitForMultipleObjects(2, hThread, TRUE, INFINITE);for (int i = 0; i < 2; i++)CloseHandle(hThread[i]);CloseHandle(g_hEmpty);CloseHandle(g_hFull);DeleteCriticalSection(&g_cs);return 0;}

 

《多线程十大经典案例之一双线程读写队列数据》运行结果:

程序运行结果如下:

本文配套程序下载地址为:http://download.csdn.net/detail/morewindows/5136035

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8646902

欢迎关注微博:http://weibo.com/MoreWindows