目录
一、输出文件有误的代码
/**
* @file mthread2.c
* @brief 多线程文件搜索
* @author zxy
* @contact
* @created 2023-7-16
* @modified 2023-7-17
**/
#include <stdio.h>
#include <dirent.h>
#include <pthread.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#define MAX_THREADS 64
#define MAX_PATH_LENGTH 1024
int total_file_count = 0;
int total_folder_count = 0;
//线程传入参数
/* struct ThreadArgs
{
char path[MAX_PATH_LENGTH];//路径
}; */
char* path;
//创建互斥锁变量
pthread_mutex_t mutex;
void* search_files_and_directories(void* arg) //线程的入口点
{
struct stat filestat;
//强制类型转换:将 void* 类型的参数 arg 转换为 struct ThreadArgs* 类型的指针 args
//struct ThreadArgs* args = (struct ThreadArgs*)arg;
// char* path = path;
// int* file_count = &(args->file_count);
// int* folder_count = &(args->folder_count);
DIR* directory;
/*
声明了一个指向目录的指针 directory。
用于保存打开的目录流的信息,方便后续的操作。
*/
struct dirent* entry;
/*
声明了一个指向目录中条目(文件或子目录)的指针 entry。
struct dirent 是一个结构体类型,用于保存目录中条目的信息,例如名称、类型等。
*/
directory = opendir(path);
if (NULL == directory) {
printf("Unable to open directory: %s\n", path);
pthread_exit(NULL);//终止“当前线程”
}
while (NULL != (entry = readdir(directory)))
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
char sub_path[MAX_PATH_LENGTH];
snprintf(sub_path, sizeof(sub_path), "%s/%s", path, entry->d_name);//整合,路径+属性
// 获取文件/文件夹信息
if (stat(sub_path, &filestat) < 0) {
printf("无法获取文件/文件夹信息:%s\n", sub_path);
continue;
}
if (S_ISDIR(filestat.st_mode))
{
pthread_mutex_lock(&mutex);
// 如果是文件夹,则增加文件夹数量,并递归调用统计子目录下的文件和文件夹数量
total_folder_count++;
pthread_mutex_unlock(&mutex);
}
else
{
pthread_mutex_lock(&mutex);
// 如果是文件,则增加文件数量
total_file_count++;
pthread_mutex_unlock(&mutex);
}
}
closedir(directory);
pthread_exit(NULL);
}
int main(int argc, char* argv[])
//argc:命令行参数个数 argv:指向字符指针数组的指针,每个字符指针指向一个命令行参数字符串。注意最后一个是一个空指针代表参数列表的结束。
{
if (argc != 2)
{
printf("Usage: %s <directory>\n", argv[0]);
return 0;
}
path = argv[1];
//初始化互斥锁
pthread_mutex_init(&mutex,NULL);
struct timeval start;
// 获取程序运行开始时间
gettimeofday(&start, NULL);//start 时间值; NULL,时区值
// 创建线程数组和线程参数数组
pthread_t threads[MAX_THREADS];//线程数组
//pthread_t是一个数据类型,表示线程标识符(线程ID)
//struct ThreadArgs thread_args[MAX_THREADS];//线程参数数组
// 遍历,初始化线程参数数组
/* for (int i = 0; i < MAX_THREADS; i++) {
strcpy(thread_args[i].path, path); // 设置搜索路径
} */
// 创建多个线程来搜索文件和文件夹
for (int i = 0; i < MAX_THREADS; i++) {
pthread_create(&threads[i], NULL, search_files_and_directories, NULL);
/*
pthread_create:用于创建线程,并将其与一个线程函数关联起来
int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg)
threat:指向pthread_类型的指针,用于存储线程ID
attr:表示线程的属性,通常使用NULL表示使用默认属性
start_routine:线程要执行的函数指针。该函数的返回类型和参数必须为void*
arg:传递给线程函数的参数
*/
}
// 等待线程完成,汇总文件和文件夹数量
for (int i = 0; i < MAX_THREADS; i++) {
pthread_join(threads[i], NULL);
/*
pthread_join:用于等待制定的线程结束
int pthread_join(pthread_t thread, void** retval)
thread:要等待的线程的ID
retval:一个双重指针,用于存储被等待线程函数的返回值
*/
}
pthread_mutex_destroy(&mutex);
// 获取程序运行结束时间
struct timeval end;
gettimeofday(&end, NULL);
// 计算程序的运行时间(单位:微秒)
long duration = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
// 获取程序的占用内存大小(单位:字节)
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
long memory_usage = usage.ru_maxrss;
// 输出统计结果和程序运行时间、内存使用情况
printf("Total number of files: %d\n", total_file_count);
printf("Total number of folders: %d\n", total_folder_count);
printf("Program duration: %ld microseconds\n", duration);
printf("Memory usage: %ld bytes\n", memory_usage);
return 0;
}
二、更改后的代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <dirent.h>
#include <string.h>
#define MAX_THREADS 64
// 定义全局变量
int totalFiles = 0;
int totalDirs = 0;
pthread_mutex_t mutex;
// 定义任务结构体
typedef struct {
char* path;
} Task;
// 递归遍历目录并统计文件和文件夹数量的函数
void countFilesAndDirs(const char* path) {
DIR* dir;
struct dirent* entry;
char fullPath[256];
// 打开目录
dir = opendir(path);
if (dir == NULL) {
return;
}
// 遍历目录中的每个项
while ((entry = readdir(dir)) != NULL) {
// 排除当前目录和上一级目录
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// 构建完整路径
snprintf(fullPath, sizeof(fullPath), "%s/%s", path, entry->d_name);
// 如果是文件夹,则递归调用该函数
if (entry->d_type == DT_DIR) {
countFilesAndDirs(fullPath);
pthread_mutex_lock(&mutex);
totalDirs++;
pthread_mutex_unlock(&mutex);
}
// 如果是文件,则增加文件计数
if (entry->d_type == DT_REG) {
pthread_mutex_lock(&mutex);
totalFiles++;
pthread_mutex_unlock(&mutex);
}
}
// 关闭目录
closedir(dir);
}
// 线程函数
void* threadFunction(void* arg) {
Task* task = (Task*) arg;
countFilesAndDirs(task->path);
free(task);
return NULL;
}
int main(int argc, char* argv[]) {
pthread_t threads[MAX_THREADS];
int numThreads;
int i;
if (argc != 2) {
printf("Usage: %s directory_path\n", argv[0]);
return 1;
}
if (pthread_mutex_init(&mutex, NULL) != 0) {
printf("Mutex initialization failed.\n");
return 1;
}
// 创建多个线程进行处理
numThreads = argc < MAX_THREADS ? argc - 1 : MAX_THREADS;
for (i = 0; i < numThreads; i++) {
Task* task = (Task*) malloc(sizeof(Task));
task->path = argv[i + 1];
pthread_create(&threads[i], NULL, threadFunction, (void*) task);
}
// 等待线程结束
for (i = 0; i < numThreads; i++) {
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&mutex);
// 打印结果
printf("Total files: %d\n", totalFiles);
printf("Total directories: %d\n", totalDirs);
return 0;
}