操作系统实践 job10

目录

1. 串行查找 job10/sfind.c

1.1 功能

1.2 实现思路

1.3  结果展示 

2. 并行查找 job10/pfind.c

2.1 功能

2.2 图示

2.3 参考代码

2.4 实现思路

 2.5 结果展示

1. 串行查找 job10/sfind.c

1.1 功能

程序 sfind 在文件或者目录中查找指定的字符串,并打印包含该字符串的行,示例如下:

  1. 在文件 file.c 中查找字符串 main
    1. 找到包含字符串 main 的行
    2. 打印文件名和该行
    3. 在目录 test 中查找字符串 main
  2. 假设目录 test 下存在文件
    1. test/hello/hello.c
    2. test/world/world.c
    3. 对目录 test 下的所有文件进行查找
      1. 找到包含字符串 main 的行
      2. 打印文件名和该行

1.2 实现思路

前置知识:操作系统实践 job4_bulibuli蛋的博客-CSDN博客

就是比较简单的文件目录遍历。

需要用到DIR,dirent,stat这三个结构体,具体见job4和注释。

  1. 主函数用stat判断文件类型
  2. 子函数用DIR打开目录,用dirent遍历目录下文件
  3. strstr函数,判断子串。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<dirent.h>
#include<sys/stat.h>
#include<unistd.h>

void find_file(char *path,char *target)
{
	//printf("enter find file fun\n");
	FILE *file=fopen(path,"r");
	char line[256];
	while(fgets(line,sizeof(line),file)){
		if(strstr(line,target))
			printf("%s:%s",path,line);
	}
	fclose(file);
}
//search the dir and find the file
void find_dir(char *path,char *target)
{
	//printf("enter find dir fun\n");
	DIR *dir=opendir(path);//open the dir
	struct dirent *entry;
	while(entry=readdir(dir))//read the dir & point to next obj
	{
		if(strcmp(entry->d_name,".")==0)
			continue;
		if(strcmp(entry->d_name,"..")==0)
			continue;
		char base[80]={0};
		strcpy(base,path);
		strcat(base,"/");
		strcat(base,entry->d_name);//fill the path
		//printf("base %s\n",base);
		if(entry->d_type==DT_DIR)//file type is dir
		{
			//printf("dir %s\n",entry->d_name);
			find_dir(base,target);
		}
		else if(entry->d_type==DT_REG)
		{
			//printf("file %s\n",entry->d_name);
			find_file(base,target);
		}
	}
	closedir(dir);
}
int main(int argc,char *argv[])
{
	if(argc!=3)
	{
		puts("usage: sfind file string");
		return 0;
	}
	char *path = argv[1];
	char *string = argv[2];

	struct stat info;
	stat(path,&info);
	if(S_ISDIR(info.st_mode))
		find_dir(path,string);
	else
		find_file(path,string);
	return 0;
}

1.3  结果展示 

 生成如下文件树:

hello.c和world.c和find.c是从sfind.c里复制过去的.

2. 并行查找 job10/pfind.c

2.1 功能

功能与 sfind 相同

  1. 要求使用多线程完成
  2. 主线程创建若干个子线程
    1. 主线程负责遍历目录中的文件,遍历到目录中的叶子节点时,将叶子节点发送给子线程进行处理
    2. 两者之间使用生产者消费者模型通信,主线程生成数据,子线程读取数据

2.2 图示

  1. 主线程创建 2 个子线程
  2. 主线程遍历目录 test 下的所有文件 把遍历的叶子节点 path 和目标字符串 string,作为任务,发送到任务队列
  3. 子线程 不断的从任务队列中读取任务 path 和 string 在 path 中查找字符串 string

2.3 参考代码

2.4 实现思路

换句话说就是

  • 主线程负责递归遍历目录找到叶子节点,并将路径加入任务队列中(任务队列类似于生产者消费者问题,主线程类似于生产者)
  • 子线程负责从任务队列取出任务,并处理子串问题,类似于消费者。
  • 特殊任务:is_end属性,如果子任务结束,就要产生特殊任务,告诉进程结束任务。

生产者消费者问题我这用了信号量请看job9 操作系统实践 job9 基于信号量实现线程同步_bulibuli蛋的博客-CSDN博客

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<stdlib.h>

#define WORKER_NUMBER 4
#define CAPACITY 100
int in=0,out=0;

//任务队列
struct Task{
	int is_end;
	char path[128];
	char string[128];
}buffer[CAPACITY];

//取任务
struct Task get_item()
{
	struct Task item;
	item=buffer[out];
	out=(out+1)%CAPACITY;
	return item;
}

//放任务
void put_item(struct Task item)
{
	buffer[in]=item;
	in=(in+1)%CAPACITY;
}

//信号量
typedef struct{
	int value;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
}sema_t;

sema_t mutex_sema;//互斥信号量
sema_t empty_buffer_sema;//空信号量
sema_t full_buffer_sema;//满信号量

//信号量初始化
void sema_init(sema_t *sema,int value)
{
	sema->value=value;
	pthread_mutex_init(&sema->mutex,NULL);
	pthread_cond_init(&sema->cond,NULL);
}

//p操作
void sema_wait(sema_t *sema)
{
	pthread_mutex_lock(&sema->mutex);
	while(sema->value<=0)
	{
		pthread_cond_wait(&sema->cond,&sema->mutex);
	}
	sema->value--;
	pthread_mutex_unlock(&sema->mutex);
}

//v操作
void sema_signal(sema_t *sema)
{
	pthread_mutex_lock(&sema->mutex);
	++sema->value;
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}

//消费者
void *worker_entry(void *arg)
{
	struct Task worker;
	while(1)
	{
		sema_wait(&full_buffer_sema);
		sema_wait(&mutex_sema);

		worker=get_item();
		if(worker.is_end)
		{
			break;
		}
		find_file(worker.path,worker.string);

		sema_signal(&mutex_sema);
		sema_signal(&empty_buffer_sema);
	}
	if(worker.is_end)
	{
		sema_signal(&mutex_sema);
        sema_signal(&empty_buffer_sema);
	}
}

//找子串函数
void find_file(char *path,char *target)
{
	//printf("enter find file fun\n");
	FILE *file=fopen(path,"r");
	char line[256];
	while(fgets(line,sizeof(line),file)){
		if(strstr(line,target))
			printf("%s:%s",path,line);
	}
	fclose(file);
}

//生产者
void find_dir(char *path,char *target)
{
	//printf("enter find dir fun\n");
	DIR *dir=opendir(path);//open the dir
	struct dirent *entry;
	while(entry=readdir(dir))//read the dir & point to next obj
	{
		if(strcmp(entry->d_name,".")==0)
			continue;
		if(strcmp(entry->d_name,"..")==0)
			continue;
		char base[80]={0};
		strcpy(base,path);
		strcat(base,"/");
		strcat(base,entry->d_name);//fill the path
		//printf("base %s\n",base);
		if(entry->d_type==DT_DIR)//file type is dir
		{
			//printf("dir %s\n",entry->d_name);
			find_dir(base,target);
		}
        //将叶子路径放入任务队列
		//put the leaf path into task list
		else if(entry->d_type==DT_REG)
		{
			//printf("file %s\n",entry->d_name);
			sema_wait(&empty_buffer_sema);
			sema_wait(&mutex_sema);
			
			struct Task item;
			item.is_end=0;
			strcpy(item.path,base);
			strcpy(item.string,target);
			put_item(item);

			sema_signal(&mutex_sema);
			sema_signal(&full_buffer_sema);

			
		}
	}
	closedir(dir);
}
int main(int argc,char *argv[])
{
	char *path=argv[1];
	char *target=argv[2];
	if(argc!=3)
	{
		puts("usage: sfind file string");
		return 0;
	}
	struct stat info;
	stat(path,&info);
//如果是目录,就是生产者消费者问题,
	if(S_ISDIR(info.st_mode))
	{
    //初始化信号量
		pthread_t consumer_tid[WORKER_NUMBER];
		sema_init(&mutex_sema,1);
		sema_init(&empty_buffer_sema,CAPACITY-1);
		sema_init(&full_buffer_sema,0);
		
		find_dir(path,target);
	    
        //开子线程
		for(int i=0;i<WORKER_NUMBER;i++)
        {

                    pthread_create(&consumer_tid[i],NULL,worker_entry,NULL);
        } 

        //结束工作
		for(int i=0;i<WORKER_NUMBER;i++)
        {
			        sema_wait(&empty_buffer_sema);
               		sema_wait(&mutex_sema);
                	struct Task item;
                	item.is_end=1;
                	put_item(item);
                	sema_signal(&mutex_sema);
                	sema_signal(&full_buffer_sema);
         }
        //让没运行完的运行完
		for(int i=0;i<WORKER_NUMBER;i++)
        {

                    pthread_join(consumer_tid[i],NULL);
        }
		return 0;

	}
    //如果是文件,就直接找子串
	else find_file(path,target);
	return 0;
}

 2.5 结果展示

猜你喜欢

转载自blog.csdn.net/LarsGyonX/article/details/125010974
今日推荐