1.10 编程之美-双线程下载[double threads to download]
【本文链接】
http://www.cnblogs.com/hellogiser/p/double-threads-to-download-and-write.html
【题目】
网络上下载数据,然后存储到硬盘上。简单做法是:先下载一块然后写到硬盘,然后再下载,再写到硬盘上。
缺点:需要先下载完才能写入硬盘,下载和写是串行操作。
改进:让两个线程并行进行,设置缓冲区,采用信号量的形式。
下载线程,只要缓冲区有空余就下载,下载完成之后告诉写线程缓冲区有数据了。
写线程,只要缓冲区有数据就写入,写完后告诉下载线程缓冲区有空闲了。
【代码】
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
//
/* version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/7/4 */ //---------------------API------------------------------ //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 disk bool 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 1000 //缓冲区数组,模拟循环队列 Block 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(); } |
【参考】
http://www.cnblogs.com/daniagger/archive/2012/03/23/2413764.html
http://www.cnblogs.com/youxin/p/3586975.html
http://blog.csdn.net/tianshuai1111/article/details/7692213
【本文链接】
http://www.cnblogs.com/hellogiser/p/double-threads-to-download-and-write.html