1.10 双线程高效下载
我们经常需要编写程序,从网络上下载数据,然后存储到硬盘上。一个简单的做法就是下载一块数据,写入硬盘,然后再下载,再写入硬盘……不断重复这个过程,直到所有的内容下载完毕并写入硬盘为止。
现在给出以下几个前提:
1、假设所有数据块的大小都是固定的,可以使用一个全局缓冲区:
Block g_buffer[BUFFER_COUNT]
2、可以使用的API
// 下载数据到缓存
bool GetBlockFromNet(Block * out_block);
// 写数据到硬盘
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();
};
现在要求使用上面提供的API编写程序完成数据的下载和写入。
解题思路:
- 终止条件:数据全部下载完,并写入硬盘即终止。
- 线程同步量的选择:为了保证下载线程和写入线程同时工作,使用信号量semaohore。
- 下载和写入程序协同工作:即缓存区满停止下载,缓冲区为空停止写入。
- 缓冲区的数据接口,由于使用的是全局数组进行存储,可以把它当做循环队列使用。
示例代码:
// 缓冲区大小
#define BUFFER_SIZE = 100
// 缓冲区
Block g_buffer[BUFFER_SIZE];
// 下载数据线程
Thread g_getThread(getData);
// 写数据线程
Thread g_writeThread(writeData);
// 缓冲区满信号量
semaphore g_bufferFull(0, BUFFER_SIZE);
// 缓冲区空信号量
semaphore g_bufferEmpty(BUFFER_SIZE, BUFFER_SIZE);
// 下载完成标志
bool g_downloadComplete;
// 数据入索引
int in_index = 0;
// 数据出索引
int out_index = 0;
void main()
{
g_downloadComplete = false;
g_getThread.start();
g_writeThread.start();
}
// 下载数据线程
void getData()
{
while (1)
{
// 增加数据到缓冲区,空信号量减1
g_bufferEmpty.Unsignal();
g_downloadComplete = getBlockFromNet(g_buffer + in_index);
in_index = (in_index + 1) % BUFFER_SIZE;
// 增加数据到缓冲区,满信号量加1
g_bufferFull.Signal();
if (g_downloadComplete)
break;
}
}
// 写数据线程
void getData()
{
while (1)
{
// 缓冲区取出数据,满信号量减1
g_bufferFull.Unsignal();
g_downloadComplete = WriteBlockToDisk(g_buffer + out_index);
out_index = (out_index + 1) % BUFFER_SIZE;
// 缓冲区取出数据,空信号量加1
g_bufferEmpty.Signal();
if (g_downloadComplete && (in_index == out_index))
break;
}
}
本文介绍了一种利用双线程实现数据高效下载的方法,通过信号量和互斥量协调下载线程与写入线程的工作,确保数据的正确下载与存储。在固定的缓冲区大小下,下载线程与写入线程能够无缝配合,提高下载效率。
555

被折叠的 条评论
为什么被折叠?



