基本的思路:
这个问题相当于是生产者和消费者模型的问题
首先定义两个线程,一个是下载线程,一个是存储线程,下载线程将数据从网络上下载到相应的数据的缓冲区中(BLOCK组成的队列)。存储的线程从数据缓冲区中读取相应的数据,并将其写到相应的磁盘上去。
多线程同步的方式有:CriticalSection、Mutex和Semaphore(信号量)。因为CriticalSection和Mutex,将不会使下载线程和存储线程同时进行工作,影响系统的效率,所以这里采用semaphore。
信号量的含义:
信号量的特性如下:信号量是一个非负整数(表示可以利用的资源数,这里是指的是可用的数据缓冲区中BLOCK的数量),所有通过它的线程(下载线程和存储线程)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作:Unsignal 和 Signal(释放)。 当一个线程调用Unsignal操作时,它要么通过然后将信号量减一(还有相应的资源),要么一直等下去(相应的资源已经没有),直到信号量大于一或超时。Signal实际上是在信号量上执行加操作,相当于提醒别的新的线程已经可以使用被释放的资源。
核心程序
#define BUFFER_COUNT 100 //定义数据队列中数据块的数目。
//每一个数据块将是下载线程和存储线程操作的基本的单元
BLOCK g_buffer[BUFFER_COUNT];//数据缓冲区队列
Thread g_ThreadA(ProcA);//下载线程
Thread g_ThreadB(ProcB);//存储线程
//信号量,表示现在在数据队列中已经存放满数据的数据块的数量
Semaphore g_seFull(0,BUFFER_COUNT);
//信号量,表示现在在数据队列中空数据块的数量
Semaphore g_seEmpty(BUFFER_COUNT,BUFFER_COUNT);
bool g_downloadComplete = false;
int in_index = 0;//表示当前下载线程正在处理的数据块的编号
{
g_ThreadA.start();//启动下载线程
g_ThreadB.start();//启动存储线程
Wait();
}
//下载线程的工作函数
void ProcA()
{
while(true)
{
//申请一个空的数据块的资源
g_seEmpty.Unsignal();
//申请到空的数据块,向in_index指向的BLOCK下载数据
g_downloadComplete = GetBlockFromNet(g_buffer + in_index);
//in_index更新
in_index = (in_index + 1) % BUFFER_CONUT;
g_seFull.Signal();//报告又有一个新的数据块已经下载完毕,可以指向写入操作...
if(g_downloadComplete)
break;
}
}
//存储线程的工作函数
void ProcB()
{
while(true)
{
//申请一个满的数据块的资源
g_seFull.Unsignal();
//申请到满的数据块,从out_index指向的BLOCK获取数据,写入Disk。
WriteBlockToDisk(g_buffer + out_index);
//out_index更新
out_index = (out_index + 1) % BUFFER_CONUT;
g_seEmpty.Signal();//报告又有一个新的数据块已经写入完毕,可以下载覆盖其数据...
if(g_downloadComplete && out_index == in_index)
break;
}
}
这个问题相当于是生产者和消费者模型的问题
首先定义两个线程,一个是下载线程,一个是存储线程,下载线程将数据从网络上下载到相应的数据的缓冲区中(BLOCK组成的队列)。存储的线程从数据缓冲区中读取相应的数据,并将其写到相应的磁盘上去。
多线程同步的方式有:CriticalSection、Mutex和Semaphore(信号量)。因为CriticalSection和Mutex,将不会使下载线程和存储线程同时进行工作,影响系统的效率,所以这里采用semaphore。
信号量的含义:
信号量的特性如下:信号量是一个非负整数(表示可以利用的资源数,这里是指的是可用的数据缓冲区中BLOCK的数量),所有通过它的线程(下载线程和存储线程)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作:Unsignal 和 Signal(释放)。 当一个线程调用Unsignal操作时,它要么通过然后将信号量减一(还有相应的资源),要么一直等下去(相应的资源已经没有),直到信号量大于一或超时。Signal实际上是在信号量上执行加操作,相当于提醒别的新的线程已经可以使用被释放的资源。
核心程序
#define BUFFER_COUNT 100 //定义数据队列中数据块的数目。
//每一个数据块将是下载线程和存储线程操作的基本的单元
BLOCK g_buffer[BUFFER_COUNT];//数据缓冲区队列
Thread g_ThreadA(ProcA);//下载线程
Thread g_ThreadB(ProcB);//存储线程
//信号量,表示现在在数据队列中已经存放满数据的数据块的数量
Semaphore g_seFull(0,BUFFER_COUNT);
//信号量,表示现在在数据队列中空数据块的数量
Semaphore g_seEmpty(BUFFER_COUNT,BUFFER_COUNT);
bool g_downloadComplete = false;
int in_index = 0;//表示当前下载线程正在处理的数据块的编号
int out_index = 0;//表示当前存储线程正在处理的数据块的编号
{
g_ThreadA.start();//启动下载线程
g_ThreadB.start();//启动存储线程
Wait();
}
//下载线程的工作函数
void ProcA()
{
while(true)
{
//申请一个空的数据块的资源
g_seEmpty.Unsignal();
//申请到空的数据块,向in_index指向的BLOCK下载数据
g_downloadComplete = GetBlockFromNet(g_buffer + in_index);
//in_index更新
in_index = (in_index + 1) % BUFFER_CONUT;
g_seFull.Signal();//报告又有一个新的数据块已经下载完毕,可以指向写入操作...
if(g_downloadComplete)
break;
}
}
//存储线程的工作函数
void ProcB()
{
while(true)
{
//申请一个满的数据块的资源
g_seFull.Unsignal();
//申请到满的数据块,从out_index指向的BLOCK获取数据,写入Disk。
WriteBlockToDisk(g_buffer + out_index);
//out_index更新
out_index = (out_index + 1) % BUFFER_CONUT;
g_seEmpty.Signal();//报告又有一个新的数据块已经写入完毕,可以下载覆盖其数据...
if(g_downloadComplete && out_index == in_index)
break;
}
}