多线程多文件查询所使用的场景:当要查询的内容存在多个文件中,如果一个个调用,比较麻烦,所以这时可以使用多线程多文件查询,让一个线程查询一个文件,这样就可以解决一次性查询多个文件的工作。如果要查询的文件较大,可以让线程一次只执行一部分,等当前线程查询结束时,清理此线程所占用的空间,然后再载入其它线程继续查询。
本程序 查询了10个文件的,使用了10个线程,而一次加载10个文件到内存中,如果内存空间较小,可以分批次的加载线程,即一次可以加载5个线程进行查询,查询结束后清理内存空间后再加载其它线程这样可以有效的利用内存空间不是很的机器,进行大数据的查询。
这里有个问题是当释放所使用的内存时,如果使用malloc()进行分配时,使用free()进行释放就会出错,而使用 calloc() 进行分配使用free()进行释放就不会出错。不知道为什么......
详见下面代码:
//多文件多线程查询,即一个文件一个线程进行查询。
// 这儿最大的问题是 使用了 malloc() 分配的内存,在使用 free() 进行回收时,会报错。
//而使用 calloc() 进行分配后就不会出报错,不知道是什么原因。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<process.h>
#include<string.h>
struct infos
{
//char *path; //文件名 myinfo[0].path = "d:\\text.txt";
//下面要这样赋值: strcpy(myinfo[0].path,"d:\\test.txt");或:sprintf(myinfo[0].path,"%s","d:\\test.txt");
char path[256]; //文件名 注意这二个种写法在结构体中的赋值是不一样的。
char findstr[256]; //要查询的字符串
int id; //线程id
char **g_pp; //把文件的内容载入这个地址
int length; //文件的行数
}myinfo[10] = { 0 }; //10:个结构体保存10个文件的信息
HANDLE inithd[10] = { 0 }; //10个初始化线程地址
HANDLE findhd[10] = { 0 }; //10个查询线程地址
void runthreadinit(void *p)
{
struct infos *pinfo = p;
printf("初始化线程 %d 开始执行......\n",pinfo->id);
FILE *pf = fopen(pinfo->path, "r");
if (pf != NULL) //先要确定有多少行,然后才能给分配内存
{
int k = 0;
while (!feof(pf))
{
char str[256];
fgets(str, 256, pf);
k++;
}
pinfo->length = k;
//下面要把文件装到内存中,所以要让文件回到文件开头
rewind(pf); //或用 fseek(pf,0,SEEK_SET);
//分配内存地址
/* pinfo->g_pp = malloc(sizeof(char *)*pinfo->length);
memset(pinfo->g_pp, '\0', sizeof(char *)*pinfo->length);*/
//calloc();不需要再进行初始化
pinfo->g_pp = calloc(pinfo->length, sizeof(char *));
if (!pinfo->g_pp)
{
printf("申请内存失败!\n");
return;
}
for (int i = 0; i < pinfo->length; i++)
{
char str[1024] = { 0 };
fgets(str, 1024, pf);
int length = strlen(str);
/* pinfo->g_pp[i] = malloc(sizeof(char)*length);
memset(pinfo->g_pp[i], '\0', sizeof(char)*length + 1);*/
pinfo->g_pp[i] = calloc(length + 1, sizeof(char));
if (pinfo->g_pp[i] != NULL)
{
if (pinfo->g_pp[i])
{
strcpy(pinfo->g_pp[i], str);
}
}
}
}
fclose(pf);
printf("初始化线程 %d 执行结束......\n", pinfo->id);
}
void runthreadsearch(void *p)
{
struct infos *pinfo = p;
printf("线程 %d 开始查询。\n", pinfo->id);
for (int i = 0; i < pinfo->length; i++)
{
if (pinfo->g_pp[i])
{
char *res = strstr(pinfo->g_pp[i], pinfo->findstr);
if (res)
{
printf("线程:%d 查询到 %s\n", pinfo->id, pinfo->g_pp[i]);
//Sleep(2000);
}
}
}
Sleep(2000);
printf("线程 %d 结束查询。\n", pinfo->id);
}
void freeAll(struct infos *pinfo)
{
printf("线程 %d 开始释放使用的内存空间...\n",pinfo->id);
for (int i = 0; i < pinfo->length; i++)
{
free(pinfo->g_pp[i]); //释放指针数组每一个指针指向的内存。
}
free(pinfo->g_pp);
printf("线程 %d 释放内存空间结束...\n", pinfo->id);
}
void main()
{ //初始化部分结构体数据
for (int i = 0; i < 10; i++)
{
myinfo[i].id = i + 1;
sprintf(myinfo[i].findstr, "李");
sprintf(myinfo[i].path, "E:\\qq%d.txt", i + 1);
}
Sleep(2000);
//可以每次载入5个线程,这样如果内存比较小的话,可以分次载入。
//分次载入内存时,一定要释放使用的内存。即每次释放,上次使用的内存。
for (int i = 0; i < 5; i++)
{
inithd[i] = _beginthread(runthreadinit, 0, &myinfo[i]);
}
WaitForMultipleObjects(5, inithd, TRUE, INFINITE);
for (int i = 0; i < 5; i++)
{
findhd[i] = _beginthread(runthreadsearch, 0, &myinfo[i]);
}
WaitForMultipleObjects(5, findhd, TRUE, INFINITE);
system("pause");
for (int i = 0; i < 5; i++)
{
freeAll(&myinfo[i]);
}
system("pause");
//再载入5个线程
for (int i = 0; i < 5; i++)
{
inithd[i+5] = _beginthread(runthreadinit, 0, &myinfo[i+5]);
}
WaitForMultipleObjects(5, inithd+5, TRUE, INFINITE); //inithd+5:因为前面有 5个线程被使用了,其实前面也释放,也可以继续使用。
for (int i = 0; i < 5; i++)
{
findhd[i+5] = _beginthread(runthreadsearch, 0, &myinfo[i+5]);
}
WaitForMultipleObjects(5, findhd+5, TRUE, INFINITE);
for (int i = 0; i < 5; i++)
{
freeAll(&myinfo[i+5]);
}
system("pause");
}
void main1()
{
sprintf(myinfo[0].findstr, "李");
myinfo[0].id = 1;
//myinfo[0].path = "e:\\qq1.txt";
sprintf(myinfo[0].path, "%s", "e:\\qq1.txt");
HANDLE phd1 = _beginthread(runthreadinit, 0, &myinfo[0]);
//查询前需要等待初始化线程把数据读入到内存中。
WaitForSingleObject(phd1, INFINITE);
HANDLE phd2 = _beginthread(runthreadsearch, 0, &myinfo[0]);
WaitForSingleObject(phd2, INFINITE);
system("pause");
freeAll(&myinfo[0]);
system("pause");
}