本文主要是介绍【编程之美】双线程高效下载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一,题目
网络上下载数据,然后存储到硬盘上。简单做法是:先下载一块然后写到硬盘,然后再下载,再写到硬盘上。
缺点:需要先下载完才能写入硬盘,下载和写是串行操作。
改进:让两个线程并行进行,设置缓冲区,采用信号量的形式。
下载线程,只要缓冲区有空余就下载,下载完成之后告诉写线程缓冲区有数据了。
写线程,只要缓冲区有数据就写入,写完后告诉下载线程缓冲区有空闲了。
二,核心源码
//downloads a block from Internet sequentially in each call//return true, if the entire file is downloaded, otherwise false.bool GetBlockFromNet(Block* out_block);//writes a block to hard diskbool WriteBlockToDisk(Block* in_block);class Thread{public:Thread(void (*work_func)());~Thread();void Start();void Abort();};class Semaphore{public:Semaphore(int count,int max_count);~Semaphore();void Unsignal();void Signal();};class Mutex{public:WaitMutex();ReleaseMutex();};//----------------------------------------------------//1.确定使用信号量,而非互斥量,保证并行操作//2.当缓冲区并不满并且下载没结束时,下载线程运行//3.当缓冲区并不空并且下载没结束时,存储线程运行#define MAX_COUNT 1000Block g_Buffer[MAX_COUNT]; //缓冲区数组,模拟循环队列Thread g_Download(ProcA);Thread g_Write(ProcB);//一开始缓冲区空间为MAX_COUNT,整个缓冲区可供下载的数据填充Semaphore ForDownload(MAX_COUNT,MAX_COUNT);//一开始缓冲区无数据可供存储Semaphore ForWrite(0,MAX_COUNT);//下载任务是否完成bool isDone;//下载的数据从缓冲区的哪个地方开始填充int in_index;//存储的数据从缓冲区的哪个地方开始提取int out_index;void ProcA()//下载线程 {while(true){//首先取得一个空闲空间,以便下载数据填充ForDownload.Unsignal();//填充isDone=GetBlockFromNet(g_Buffer+in_index);//更新索引in_index=(in_index+1)%MAX_COUNT;//提示存储线程可以工作ForWrite.Signal();//当任务全部下载完成,进程就可以结束了if(isDone)break;}}void ProcB()//写入线程 {while(true){//查询时候有数据可供存储ForWrite.Unsignal();//存储WriteBlockToDisk(g_Buffer+out_index);//更新索引out_index=(out_index+1)%MAX_COUNT;//将空闲空间还给缓冲区ForDownload.Signal();//当任务全部下载完成,并且所有的数据都存储到硬盘中,进程才可以结束if(isDone&&in_index==out_index)break;}}int main(){isDone=false;in_index=0;out_index=0;g_Download.Start();g_Write.Start();}
这篇关于【编程之美】双线程高效下载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!