Ошибка чтения размера файла в поточном приложении (linux, pthreads) - PullRequest
1 голос
/ 27 января 2012

Я пытаюсь прочитать все файлы и каталоги из папки в 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;
}

Ответы [ 2 ]

1 голос
/ 27 января 2012

Я бы рекомендовал вам проверить возвращаемое значение из вызовов stat (), которые вы делаете.

В рабочем потоке вы печатаете thentry.d_name, который выглядит хорошо, но без информации о пути относительно вашего рабочего каталога я считаю, что вызов stat(thentry.d_name,&thstat); завершится неудачей.

0 голосов
/ 27 января 2012

Я бы не рекомендовал создавать отдельный поток для сканирования каждого каталога. Эта программа связана с вводом / выводом, поэтому она не будет работать быстрее при использовании нескольких потоков. Во всяком случае, он будет работать медленнее, потому что несколько потоков читают из разных мест одновременно, заставляя диск искать много.

Было бы лучше, если бы вы использовали один поток и выполняли простой обход дерева каталогов по глубине или по ширине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...