秒杀多线程第十五篇 多线程十大经典案例之一 双线程读写队列数据
2013-03-22 11:01
441 查看
秒杀多线程第十五篇 多线程十大经典案例之一 双线程读写队列数据
MFC对话框中一个按钮的响应函数实现两个功能:
显示数据同时处理数据,因此开两个线程,一个线程显示数据(开了一个定时器,响应WM_TIMER消息按照一定时间间隔向TeeChart图表添加数据并显示)同时在队列队尾添加数据,另一个线程从该队列队头去数据来处理。
下面就来解决这个案例。先来分析下。
这个案例是一个线程向队列中的队列头部读取数据,一个线程向队列中的队列尾部写入数据。看起来很像读者写者问题(见《秒杀多线程第十一篇读者写者问题》和《秒杀多线程第十四篇读者写者问题继读写锁SRWLock》),但其实不然,如果将队列看成缓冲区,这个案例明显是个生产者消费者问题(见《秒杀多线程第十篇生产者消费者问题》)。因此我们仿照生产者消费者的思路来具体分析下案例中的“等待”情况:
1. 当队列为空时,读取数据线程必须等待写入数据向队列中写入数据。也就是说当队列为空时,读取数据线程要等待队列中有数据。
2. 当队列满时,写入数据线程必须等待读取数据线程向队列中读取数据。也就是说当队列满时,写入数据线程要等待队列中有空位。
在访问队列时,需要互斥吗?这将依赖于队列的数据结构实现,如果使用STL中的vector,由于vector会动态增长。因此要做互斥保护。如果使用循环队列,那么读取数据线程拥有读取指针,写入数据线程拥有写入指针,各自将访问队列中不同位置上的数据,因此不用进行互斥保护。
分析完毕后,再来考虑使用什么样的数据结构,同样依照《秒杀多线程第十篇生产者消费者问题》中的做法。使用两个信号量,一个来记录循环队列中空位的个数,一个来记录循环队列中产品的个数(非空位个数)。代码非常容易写出,下面给出完整的源代码。
[cpp] view
plaincopy
//秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
//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;
}
程序运行结果如下:
《多线程十大经典案例之一双线程读写队列数据》案例描述:
MFC对话框中一个按钮的响应函数实现两个功能:显示数据同时处理数据,因此开两个线程,一个线程显示数据(开了一个定时器,响应WM_TIMER消息按照一定时间间隔向TeeChart图表添加数据并显示)同时在队列队尾添加数据,另一个线程从该队列队头去数据来处理。
下面就来解决这个案例。先来分析下。
《多线程十大经典案例之一双线程读写队列数据》案例分析:
这个案例是一个线程向队列中的队列头部读取数据,一个线程向队列中的队列尾部写入数据。看起来很像读者写者问题(见《秒杀多线程第十一篇读者写者问题》和《秒杀多线程第十四篇读者写者问题继读写锁SRWLock》),但其实不然,如果将队列看成缓冲区,这个案例明显是个生产者消费者问题(见《秒杀多线程第十篇生产者消费者问题》)。因此我们仿照生产者消费者的思路来具体分析下案例中的“等待”情况:1. 当队列为空时,读取数据线程必须等待写入数据向队列中写入数据。也就是说当队列为空时,读取数据线程要等待队列中有数据。
2. 当队列满时,写入数据线程必须等待读取数据线程向队列中读取数据。也就是说当队列满时,写入数据线程要等待队列中有空位。
在访问队列时,需要互斥吗?这将依赖于队列的数据结构实现,如果使用STL中的vector,由于vector会动态增长。因此要做互斥保护。如果使用循环队列,那么读取数据线程拥有读取指针,写入数据线程拥有写入指针,各自将访问队列中不同位置上的数据,因此不用进行互斥保护。
分析完毕后,再来考虑使用什么样的数据结构,同样依照《秒杀多线程第十篇生产者消费者问题》中的做法。使用两个信号量,一个来记录循环队列中空位的个数,一个来记录循环队列中产品的个数(非空位个数)。代码非常容易写出,下面给出完整的源代码。
《多线程十大经典案例之一双线程读写队列数据》完整代码:
[cpp] viewplaincopy
//秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
//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;
}
《多线程十大经典案例之一双线程读写队列数据》运行结果:
程序运行结果如下:相关文章推荐
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据
- 【多线程】(十二)多线程十大经典案例之一双线程读写队列数据
- 多线程十大经典案例之一 双线程读写队列数据
- 多线程15: 多线程十大经典案例之一 双线程读写队列数据
- java多线程:16、阻塞队列【BlockingQueue】实现线程数据共享的效果
- 秒杀多线程系列之⑤ 经典线程之同步 关键段实现互斥
- linux c++多线程 线程私有数据 互斥量 条件变量 信号量 读写锁 自旋锁 屏障
- 2.使用synchronized关键字实现多线程的同步和互斥(不同线程同时读写同一数据)
- JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池
- 秒杀多线程-经典线程同步之信号量Semaphore
- 深入浅出Win32多线程设计之MFC的多线程-线程与消息队列(经典)