编程之美--双线程高效下载

一,题目

        网络上下载数据,然后存储到硬盘上。简单做法是:先下载一块然后写到硬盘,然后再下载,再写到硬盘上。

        缺点:需要先下载完才能写入硬盘,下载和写是串行操作。

        改进:让两个线程并行进行,设置缓冲区,采用信号量的形式。

                    下载线程,只要缓冲区有空余就下载,下载完成之后告诉写线程缓冲区有数据了。

                     写线程,只要缓冲区有数据就写入,写完后告诉下载线程缓冲区有空闲了。

        

二,核心源码

[html] 
view plain
copy

  1. //downloads a block from Internet sequentially in each call  
  2. //return true, if the entire file is downloaded, otherwise false.  
  3. bool GetBlockFromNet(Block* out_block);  
  4.   
  5. //writes a block to hard disk  
  6. bool WriteBlockToDisk(Block* in_block);  
  7.   
  8. class Thread  
  9. {  
  10. public:  
  11.     Thread(void (*work_func)());  
  12.     ~Thread();  
  13.     void Start();  
  14.     void Abort();  
  15. };  
  16.   
  17. class Semaphore  
  18. {  
  19. public:  
  20.     Semaphore(int count,int max_count);  
  21.     ~Semaphore();  
  22.     void Unsignal();  
  23.     void Signal();  
  24. };  
  25.   
  26. class Mutex  
  27. {  
  28. public:  
  29.     WaitMutex();  
  30.     ReleaseMutex();  
  31. };  
  32. //—————————————————-  
  33.   
  34.   
  35.   
  36. //1.确定使用信号量,而非互斥量,保证并行操作  
  37. //2.当缓冲区并不满并且下载没结束时,下载线程运行  
  38. //3.当缓冲区并不空并且下载没结束时,存储线程运行  
  39.   
  40.   
  41. #define MAX_COUNT 1000  
  42. Block g_Buffer[MAX_COUNT]; //缓冲区数组,模拟循环队列  
  43. Thread g_Download(ProcA);  
  44. Thread g_Write(ProcB);  
  45.   
  46. //一开始缓冲区空间为MAX_COUNT,整个缓冲区可供下载的数据填充  
  47. Semaphore ForDownload(MAX_COUNT,MAX_COUNT);  
  48. //一开始缓冲区无数据可供存储  
  49. Semaphore ForWrite(0,MAX_COUNT);  
  50.   
  51. //下载任务是否完成  
  52. bool isDone;  
  53. //下载的数据从缓冲区的哪个地方开始填充  
  54. int in_index;  
  55. //存储的数据从缓冲区的哪个地方开始提取  
  56. int out_index;  
  57.   
  58. void ProcA()//下载线程   
  59. {  
  60.     while(true)  
  61.     {  
  62.         //首先取得一个空闲空间,以便下载数据填充  
  63.         ForDownload.Unsignal();  
  64.         //填充  
  65.         isDone=GetBlockFromNet(g_Buffer+in_index);  
  66.         //更新索引  
  67.         in_index=(in_index+1)%MAX_COUNT;  
  68.         //提示存储线程可以工作  
  69.         ForWrite.Signal();  
  70.       
  71.         //当任务全部下载完成,进程就可以结束了  
  72.         if(isDone)  
  73.               break;  
  74.     }  
  75. }  
  76.   
  77. void ProcB()//写入线程   
  78. {  
  79.     while(true)  
  80.     {  
  81.         //查询时候有数据可供存储  
  82.         ForWrite.Unsignal();  
  83.         //存储  
  84.         WriteBlockToDisk(g_Buffer+out_index);  
  85.         //更新索引  
  86.         out_index=(out_index+1)%MAX_COUNT;  
  87.         //将空闲空间还给缓冲区  
  88.         ForDownload.Signal();  
  89.       
  90.         //当任务全部下载完成,并且所有的数据都存储到硬盘中,进程才可以结束  
  91.         if(isDone&&in_index==out_index)  
  92.             break;  
  93.     }  
  94. }  
  95.   
  96. int main()  
  97. {  
  98.     isDone=false;  
  99.     in_index=0;  
  100.     out_index=0;  
  101.     g_Download.Start();  
  102.     g_Write.Start();  
  103. }  
    原文作者:笨蛋糕
    原文地址: https://blog.csdn.net/woshibendangao/article/details/39120347
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞