//多线程读取文件,同时把读取到的文件内容再用多线程写入到指定的空白文件中,实现多线程读写文件
//从程序中可以看到使用WaitForSingleObject()函数。来控制多线程访问同一文件时不至于发生冲突。通过CEvent g_fileReadEvent, g_fileWriteEvent;这两个变量的ResetEvent()函数和SetEvent()函数来设置信号量的nonsignaled和signaled状态。其用法可以看下文红色字迹所示
struct filePart
{
int nBegin;
int nCur; // 文件指针现在的位置,用于读取
int nPre; // 文件指针原先的位置,用于写入
int nEnd;
CWinThread * pThread; // 记录线程活动情况
};
CEvent g_fileReadEvent, g_fileWriteEvent;
bool DealFileThread(CString fileName, filePart * pFilePart_STR) //随便写个函数说明
{
FILE *file;
int readLen ;
//MAX_BUFFER_LEN 在头文件里定义,这里能够保证数据不丢失,也不至于内存逸出
char *buffer = new char[MAX_BUFFER_LEN];
while (pFilePart_STR->nCur < pFilePart_STR->nEnd) // 线程没有完成自己的模块就不能退出
{
WaitForSingleObject(g_fileReadEvent, INFINITE); // nonsignaled就等,在线程运行之前,先调用 g_fileReadEvent.SetEvent();和 g_fileWriteEvent.SetEvent();使该信号量处在signaled状态。
g_fileReadEvent.ResetEvent(); // 设为nonsignaled状态,这时其它的线程已经不能访问文件了,只有等待,而且是不耗资源的等待。
file = fopen(fileName,"r+b");
if (NULL != fpThreadLog)
{
fprintf(fpThreadLog, "thread %d writing/n", pFilePart_STR->pThread->m_nThreadID);
}
if(file == NULL)
return false;
// SEEK_CUR//:Current position of file pointer
// SEEK_END//:End of file
// SEEK_SET//:Beginning of file
fseek(file, pFilePart_STR->nCur, SEEK_SET/*从开头开始读取文件*/); // 指针到该线程读取文件块位置的开头,准备读取文件
readLen = fread(buffer, sizeof(char), MAX_BUFFER_LEN, file);// 读取该位置文件的二进制内容
pFilePart_STR->nPre = pFilePart_STR->nCur; // 现在指针的位置已经变了,所以记录到前一个位置上
pFilePart_STR->nCur = ftell(file); // 记录现在文件指针的位置
fclose(file); //释放资源
g_fileReadEvent.SetEvent(); // 设为signaled状态,对文件的读取操作完成后,设置信号量为singaled状态,让其它线程能访问已经释放的资源。
WaitForSingleObject(g_fileWriteEvent, INFINITE);
g_fileWriteEvent.ResetEvent();
FILE *fpToWrite = fopen(strToWrite, "r+b"); // 打开待写文件
if (NULL == fpToWrite)
{
return false;
}
fseek(fpToWrite, pFilePart_STR->nPre, SEEK_SET); // 在刚才记录二进制内容的文件位置上写入
fwrite(buffer, sizeof(char), MAX_BUFFER_LEN, fpToWrite); // 写二进制内容
fclose(fpToWrite);
g_fileWriteEvent.SetEvent();
}
delete[] buffer; // 释放空间
return true;
}
通过实验可以看出,WaitForSingleObject方法的效率确实很高!