Я пытаюсь прочитать все файлы и каталоги из папки в Linux с потоками для
получить максимальный размер и имя файла в текущем каталоге и текущем дереве каталогов.
Основной поток сканирует файлы, находящиеся в базовом каталоге, и, когда каталог найден, создается новый поток для продолжения сканирования.
На этом этапе потоки присоединяются, пока не закончится последний созданный поток.
(Я знаю, что это не лучший способ сделать это, но это всего лишь практика.)
Проблема в том, что программа возвращает неправильные результаты, и я не знаю, почему.
У меня есть следующее дерево файлов для тестирования приложения:
. ( Debug folder under codelite project / workspace )
├── [ 4096] dir1
│ └── [ 9] arch-dir1.txt
├── [ 4096] dir2
│ ├── [ 27] arch-dir2.txt
│ └── [ 29083] huge
├── [ 29053] direxp
├── [ 27048] direxp.o
└── [ 68] direxp.o.d
Как вы можете видеть самый большой размер файла в текущей директории, это direxp (эта программа) и самый большой размер файла в древовидной структуре, он огромен
Запустив бинарный файл, я получил следующие результаты:
dir: .
dir: ..
arch: direxp.o.d
max dir & tree set to: direxp.o.d size: 68
arch: direxp.o
max file dir set to: direxp.o size: 27048
arch: .d
arch: direxp
max file dir set to: direxp size: 29053
dir: dir1
th dir: .
th dir: ..
th arch: arch-dir1.txt thsize: 4096
max tree file set to: arch-dir1.txt thsize: 4096
dir: dir2
th dir: .
th dir: ..
th arch: arch-dir2.txt thsize: 4096
th arch: huge thsize: 4096
Highest current directory file:
direxp tam:29053 bytes.
Highest tree file:
arch-dir1.txt tam:4096 bytes.
Строки с префиксом th показывают данные, обработанные в другом потоке.
Я использую функции readdir (основной поток) и readdir_r (порожденный поток) для чтения записей каталога.
Я думал, что это может быть проблемой, но позже скомпилировал программу, вызывающую readdir_r для всех потоков, и неправильные результаты сохраняются.
Действительно, я не понимаю, почему размер файла возвращается неверно (4096, это размер кластера по умолчанию в моей файловой системе. Так почему файлы обрабатываются как каталоги?
Не могли бы вы мне помочь?
Спасибо
код основной функции
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <pthread.h>
using std::cout;
using std::cin;
using std::endl;
#define MAX_PATH 255
struct archivo
{
char nombre[MAX_PATH+1];
off_t tam;
};
// thread args
struct thargs
{
char nextdir[MAX_PATH+1]; // next dir
void* (*pth)(void*); // pointer to thread function
archivo* arch; // pointer to archivo
};
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int main(int argc, char **argv)
{
char target[MAX_PATH+1] = {0}; // directorio inicial
archivo grande_dir ={{0}},grande_arbol = {{0}};
// No params
if ( argc < 2)
{
if ( ! getcwd(target,MAX_PATH) )
{
perror("Error en path:");
exit(-1);
}
}
if ( argc == 2)
strncpy(target,argv[1],MAX_PATH);
if ( argc > 2)
{
perror("Num params incorrecto");
exit(-2);
}
DIR* midir = NULL;
// try to open target dir
if ( ! (midir = opendir(target) ) )
{
perror("Error abriendo dir:");
exit(-3);
}
dirent* direntry;
//dirent* rentry1 = NULL;
struct stat estado = {0}; // struct needed for desambiguation
bool primera = true; // control var to initialize the search
// read current dir contents
//while( (readdir_r(midir,&direntry,&rentry1) == 0 ) && rentry1 )
while( (direntry = readdir(midir) ) )
{
stat(direntry->d_name,&estado);
// current entry it's a file
if ( direntry->d_type == DT_REG )
{
cout << "arch: " << direntry->d_name << endl;
// init search to find the highest file
if (primera)
{
strncpy(grande_dir.nombre,direntry->d_name,MAX_PATH);
grande_dir.tam = estado.st_size;
strncpy(grande_arbol.nombre,direntry->d_name,MAX_PATH);
grande_arbol.tam = estado.st_size;
primera = false;
cout << "max dir & tree set to: " << direntry->d_name << " size: " << estado.st_size << endl;
}
// High file size
if ( estado.st_size > grande_dir.tam)
{
pthread_mutex_lock(&lock);
strncpy(grande_dir.nombre,direntry->d_name,MAX_PATH);
grande_dir.tam = estado.st_size;
pthread_mutex_unlock(&lock);
cout << "max file dir set to: " << direntry->d_name << " size: " << estado.st_size << endl;
}
}
// current entry it's a directory
if ( direntry->d_type == DT_DIR )
{
cout << "dir: " << direntry->d_name << endl;
// check not . or .. dir
if ( (strcmp(direntry->d_name,".") != 0) && (strcmp(direntry->d_name,"..") != 0 ) )
{
thargs args = {{0}};
pthread_t th1;
pthread_mutex_lock(&lock);
sprintf(args.nextdir,"%s/%s",target,direntry->d_name);
args.arch = &grande_arbol;
args.pth = &procesadir;
pthread_mutex_unlock(&lock);
// new thread creation
pthread_create(&th1,NULL,procesadir,&args);
// main thread waits th1 completion
pthread_join(th1, NULL);
}
}
}
closedir(midir);
pthread_mutex_destroy(&lock);
cout << endl << "Highest file in current directory file :" << endl
<< grande_dir.nombre << " tam:" << grande_dir.tam
<< " bytes." << endl;
cout << endl << "Highest file in tree:" << endl
<< grande_arbol.nombre << " tam:" << grande_arbol.tam
<< " bytes." << endl;
return 0;
}
код функции нити
void* procesadir(void* args)
{
thargs* myargs = reinterpret_cast<thargs*>(args);
DIR* thdir = NULL;
if ( (thdir = opendir(myargs->nextdir) ) )
{
dirent thentry;
dirent* rentry = NULL;
struct stat thstat = {0};
//while( (thentry = readdir(thdir) ) )
while( (readdir_r(thdir,&thentry,&rentry) == 0 ) && rentry )
{
stat(thentry.d_name,&thstat);
if ( thentry.d_type == DT_REG )
{
cout << " th arch: " << thentry.d_name << " thsize: " << thstat.st_size << endl;
if ( thstat.st_size > myargs->arch->tam)
{
pthread_mutex_lock(&lock);
memset(myargs->arch->nombre,0,MAX_PATH);
strncpy(myargs->arch->nombre,thentry.d_name,MAX_PATH);
myargs->arch->tam = thstat.st_size;
pthread_mutex_unlock(&lock);
cout << "max tree file set to: " << thentry.d_name << " thsize: " << thstat.st_size << endl;
}
}
if ( thentry.d_type == DT_DIR )
{
if ( (strcmp(thentry.d_name,".") != 0) && (strcmp(thentry.d_name,"..") != 0 ) )
{
thargs largs = {{0}};
pthread_t th2;
sprintf(largs.nextdir,"%s/%s",myargs->nextdir,thentry.d_name);
largs.arch = myargs->arch;
largs.pth = myargs->pth;
// thread creation
pthread_create(&th2,NULL,procesadir,&args);
// current thread waits th2 completion
pthread_join(th2, NULL);
}
cout << " th dir: " << thentry.d_name << endl;
}
}
closedir(thdir);
else
perror("Error abriendo dir en thread:");
return 0;
}