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