zoukankan      html  css  js  c++  java
  • 多线程面试题系列(16):多线程十大经典案例之一 双线程读写队列数据

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

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

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

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

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

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

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

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

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

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

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

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

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

    [cpp] view plain copy
     
    1. //第十六篇 多线程十大经典案例之一 双线程读写队列数据  
    2. //http://blog.csdn.net/MoreWindows/article/details/8646902  
    3. #include <stdio.h>  
    4. #include <process.h>  
    5. #include <windows.h>  
    6. #include <time.h>  
    7. const int QUEUE_LEN = 5;  
    8. int g_arrDataQueue[QUEUE_LEN];  
    9. int g_i, g_j, g_nDataNum;  
    10. //关键段 用于保证互斥的在屏幕上输出  
    11. CRITICAL_SECTION g_cs;  
    12. //信号量 g_hEmpty表示队列中空位 g_hFull表示队列中非空位  
    13. HANDLE     g_hEmpty, g_hFull;  
    14. //设置控制台输出颜色  
    15. BOOL SetConsoleColor(WORD wAttributes)  
    16. {  
    17.     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  
    18.     if (hConsole == INVALID_HANDLE_VALUE)  
    19.         return FALSE;     
    20.     return SetConsoleTextAttribute(hConsole, wAttributes);  
    21. }  
    22. //读数据线程函数  
    23. unsigned int __stdcall ReaderThreadFun(PVOID pM)  
    24. {  
    25.     int nData = 0;  
    26.     while (nData < 20)  
    27.     {  
    28.         WaitForSingleObject(g_hFull, INFINITE);  
    29.         nData = g_arrDataQueue[g_i];  
    30.         g_i = (g_i + 1) % QUEUE_LEN;  
    31.         EnterCriticalSection(&g_cs);  
    32.         printf("从队列中读数据%d ", nData);  
    33.         LeaveCriticalSection(&g_cs);  
    34.         Sleep(rand() % 300);  
    35.         ReleaseSemaphore(g_hEmpty, 1, NULL);  
    36.     }  
    37.     return 0;  
    38. }  
    39. //写数据线程函数  
    40. unsigned int __stdcall WriterThreadFun(PVOID pM)  
    41. {  
    42.     int nData = 0;  
    43.     while (nData < 20)  
    44.     {  
    45.         WaitForSingleObject(g_hEmpty, INFINITE);  
    46.         g_arrDataQueue[g_j] = ++nData;  
    47.         g_j = (g_j + 1) % QUEUE_LEN;  
    48.         EnterCriticalSection(&g_cs);  
    49.         SetConsoleColor(FOREGROUND_GREEN);  
    50.         printf("    将数据%d写入队列 ", nData);  
    51.         SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
    52.         LeaveCriticalSection(&g_cs);  
    53.         Sleep(rand() % 300);  
    54.         ReleaseSemaphore(g_hFull, 1, NULL);  
    55.     }  
    56.     return 0;  
    57. }  
    58. int main()  
    59. {  
    60.     printf("     第十六篇 多线程十大经典案例 双线程读写队列数据 ");  
    61.     printf(" - by MoreWindows( http://blog.csdn.net/MoreWindows/article/details/8646902 ) - ");  
    62.       
    63.     InitializeCriticalSection(&g_cs);  
    64.     g_hEmpty = CreateSemaphore(NULL, QUEUE_LEN, QUEUE_LEN, NULL);  
    65.     g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);  
    66.       
    67.     srand(time(NULL));  
    68.     g_i = g_j = 0;  
    69.     HANDLE hThread[2];  
    70.     hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
    71.     hThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  
    72.       
    73.     WaitForMultipleObjects(2, hThread, TRUE, INFINITE);  
    74.       
    75.     for (int i = 0; i < 2; i++)  
    76.         CloseHandle(hThread[i]);  
    77.     CloseHandle(g_hEmpty);  
    78.     CloseHandle(g_hFull);  
    79.     DeleteCriticalSection(&g_cs);  
    80.     return 0;  
    81. }  

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

    程序运行结果如下:

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

  • 相关阅读:
    HDU 3572 Task Schedule(拆点+最大流dinic)
    POJ 1236 Network of Schools(Tarjan缩点)
    HDU 3605 Escape(状压+最大流)
    HDU 1166 敌兵布阵(分块)
    Leetcode 223 Rectangle Area
    Leetcode 219 Contains Duplicate II STL
    Leetcode 36 Valid Sudoku
    Leetcode 88 Merge Sorted Array STL
    Leetcode 160 Intersection of Two Linked Lists 单向链表
    Leetcode 111 Minimum Depth of Binary Tree 二叉树
  • 原文地址:https://www.cnblogs.com/dengyungao/p/7504125.html
Copyright © 2011-2022 走看看