1.10 双线程高效下载
(一)题目
网络上下载数据,然后存储到硬盘上。简单做法是:先下载一块然后写到硬盘,然后再下载,再写到硬盘上。
缺点:需要先下载完才能写入硬盘,下载和写是串行操作。
改进:让两个线程并行进行,设置缓冲区,采用信号量的形式。
下载线程,只要缓冲区有空余就下载,下载完成之后告诉写线程缓冲区有数据了。
写线程,只要缓冲区有数据就写入,写完后告诉下载线程缓冲区有空闲了。
代码如下:
class Thread { public: Thread(void (*work_func)()); ~Thread(); void Start(); void Abort(); }; class Semaphore { public: Semaphore(int count, int max_count); ~Semaphore(); void Unsignal(); //count-- void Signal(); //count++ }; class Mutex { public: WaitMutex(); ReleaseMutex(); }; //如果使用Mutex,下载和存储线程将不能同时工作,因此,Semaphore是更好的选择 #define BUFFER_COUNT 100 Block g_buffer[BUFFER_COUNT]; Thread g_threadA(ProcA); Thread g_threadB(ProcB); Semaphore g_seFull(0, BUFFER_COUNT); //一开始缓冲区无数据可供存储 Semaphore g_seEmpty(BUFFER_COUNT, BUFFER_COUNT); //一开始缓冲区空间为BUFFER_COUNT,整个缓冲区可供下载的数据填充 bool g_downloadComplete; //下载任务是否完成 int in_index = 0; //下载的数据从缓冲区的哪个地方开始填充 int out_index = 0; //存储的数据从缓冲区的哪个地方开始提取 void main() { g_downloadComplete = false; g_threadA.Start(); g_threadB.Start(); } void ProcA() { while(true) { g_seEmpty.Unsignal(); //首先取得一个空闲空间,以便下载数据填充 g_downloadComplete = GetBlockFromNet(g_buffer + in_index); //填充 in_index = (in_index + 1) % BUFFER_COUNT; //更新索引 g_seFull.Signal(); //提示存储线程可以工作 if(g_downloadComplete) break; //当任务全部下载完成,进程就可以结束了 } } void ProcB() { while(true) { g_seFull.Unsignal(); //查询时候有数据可供存储 WriteBlockToDisk(g_buffer + out_index); //存储 out_index = (out_index + 1) % BUFFER_COUNT; //更新索引 g_seEmpty.Signal(); //将空闲空间还给缓冲区 if(g_downloadComplete && out_index == in_index) break; //当任务全部下载完成,并且所有的数据都存储到硬盘中,进程才可以结束 } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。