[编程之美] PSet1.10 双线程高效下载
2014-07-27 08:21
239 查看
一,题目
网络上下载数据,然后存储到硬盘上。简单做法是:先下载一块然后写到硬盘,然后再下载,再写到硬盘上。
缺点:需要先下载完才能写入硬盘,下载和写是串行操作。
改进:让两个线程并行进行,设置缓冲区,采用信号量的形式。
下载线程,只要缓冲区有空余就下载,下载完成之后告诉写线程缓冲区有数据了。
写线程,只要缓冲区有数据就写入,写完后告诉下载线程缓冲区有空闲了。
二,核心源码
假设单线程串行运行的情况下:
如果希望设计两个线程,使得下载和写硬盘能够并行进行。
线程A:从网络中读取一个数据块,存储到内存的缓冲区中。
线程B:从缓存中读取内容,存储到文件中。
网络上下载数据,然后存储到硬盘上。简单做法是:先下载一块然后写到硬盘,然后再下载,再写到硬盘上。
缺点:需要先下载完才能写入硬盘,下载和写是串行操作。
改进:让两个线程并行进行,设置缓冲区,采用信号量的形式。
下载线程,只要缓冲区有空余就下载,下载完成之后告诉写线程缓冲区有数据了。
写线程,只要缓冲区有数据就写入,写完后告诉下载线程缓冲区有空闲了。
二,核心源码
假设单线程串行运行的情况下:
//下面是串行实现文件下载与存储 -------API------ //从网络中下载一个数据块 bool GetBlockFromNet(BLOCK *out_Block); //将数据块信息存入硬盘 bool WriteBlockToDisk(BLOCK *in_Block); while(true){ bool IsDownloadCompleted; IsDownloadCompleted = GetBlockFromNet(g_buffer); WriteBlockToDisk(g_buffer); if(IsDownloadCompleted) break; }
如果希望设计两个线程,使得下载和写硬盘能够并行进行。
线程A:从网络中读取一个数据块,存储到内存的缓冲区中。
线程B:从缓存中读取内容,存储到文件中。
-------API------ class Thread { public: //initalize a thread and set the work function Thread(void(*work_func)()); //once the object is destructed , the thread will be aborted ~Thread(); //start the thread void Start(); //stop the thread void Abort(); }; class Semaphore { public: //initialize semaphore counts semaphore(int count , int max_count); ~semaphore(); //consume a signal (count--) , block current thread if count==0 void Unsignal(); //raise a signal (count++) void Signal(); }; //从网络中下载一个数据块 bool GetBlockFromNet(BLOCK *out_Block); //将数据块信息存入硬盘 bool WriteBlockToDisk(BLOCK *in_Block); ---------------- //分析和解法: //1.什么时候完成任务?网络数据下载完毕并完全存储到硬盘上,此时正常终止两个线程 //2.下载和存储线程工作条件? // 所有内容完全下载完毕---下载线程结束; // 下载工作完成 且 内存缓存区为空---存储线程结束; //3.共享缓存区数据结构?下载与存储应该满足“先进先出”,保证内容的正确顺序。 #define BUFFER_COUNT 1000 Block g_buffer[BUFFER_COUNT]; Thread g_Download(ProcA);//构造函数初始化两个线程 Thread g_Write(ProcB); //一开始缓存区空间为BUFFER_COUNT,整个缓存区可供下载数据填充 Semaphore ForDownload(BUFFER_COUNT , BUFFER_COUNT); //一开始缓存区无数据可供存储 Semaphore ForWrite(0 , BUFFER_COUNT); //下载任务是否完成 bool g_downloadComplete; //下载数据从缓存区哪个地方开始填充 int in_index = 0; //存储数据从缓存区哪个地方开始提取 int out_index = 0; void main() { g_downloadComplete = false; g_Download.Start(); g_Write.Start(); //wait here till threads finished } void ProcA()//下载线程 { while(true){ ForDownload.Unsignal(); g_downloadComplete = GetBlockFromNet(g_buffer + in_index); int in_index = (in_index + 1)%BUFFER_COUNT;//循环队列的方式,下标从0开始 ForWrite.Signal();//下载了一个数据块就可以释放一个数据块存储 if(g_downloadComplete) break; } } void ProcB()//存储线程 { while(true){ ForWrite.Unsignal(); WriteBlockToDisk(g_buffer + out_index); int out_index = (out_index + 1)%BUFFER_COUNT;//循环队列方式,下标从0开始 ForDownload.Signal();//存储了一个数据块就可以释放一个数据块覆盖原有数据 if(g_downloadComplete && in_index==out_index) break; } }
相关文章推荐
- 读书笔记之编程之美 - 1.10 双线程高效下载
- 编程之美--双线程高效下载
- 编程之美-双线程高效下载方法整理
- iOS并发编程指南——超级详细的指南,放弃线程,高效并发,实现完美体验吧!(更新PDF下载)
- 【编程之美】双线程高效下载
- 1.10 双线程高效下载
- 1.10 编程之美-双线程下载[double threads to download]
- 【编程之美】双线程高效下载
- 编程之美---双线程高效下载
- [编程之美]双线程高效下载
- iOS并发编程指南——超级详细的指南,放弃线程,高效并发,实现完美体验吧
- 双线程高效下载问题
- python高效编程技巧13(如何在线程之间实现事件通知)
- Java网络编程之单线程下载文件设置显示进度
- 编程之美——双线程高效下载
- 编程之美:第一章 1.10双线程高效下载
- Java网络编程之单线程下载文件设置显示进度(一)
- iOS并发编程指南——超级详细的指南,放弃线程,高效并发,实现完美体验吧!
- 《C#编程之道》 之 高效使用线程
- 第1章 游戏之乐——双线程高效下载