您的位置:首页 > 编程语言

1.10 编程之美-双线程下载[double threads to download]

2014-07-04 09:12 302 查看
【本文链接】

/article/5268978.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();

}

【参考】

/article/6256094.html

/article/4744998.html

/article/1413049.html

【本文链接】

/article/5268978.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: