【本文鏈接】
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