Russian Qt Forum
Май 02, 2024, 14:32 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Многопоточное копирование файлов (Linux)  (Прочитано 10895 раз)
toggetit
Гость
« : Сентябрь 29, 2010, 16:30 »

Добрый день, форумчане!
Я тут начал изучать потоки и натнулся на такую задачку - создать программу, которая копирует структуру исходной директории в целевую, при этом для копирования файла создаётся отдельный поток и для директорий (проход/копирование) тоже отдельный. Начал писать такую программу, используя стандартные потоки линукс (phtread.h), ибо пока хочется изучить как оно работает, так сказать, нативно. Для навигации решил использовать Qt (QDir, QFileInfo etc.). При проходе/создании структуры папок вроде всё работает и очень хорошо (при этом прирост производительности в 15 раз по сравнению с однопоточным приложением), а вот как начинаю копировать файлы - облом! Сегфол! При этом если дожидаться завершения потока (pthread_join), то всё работает отлично. Уважаемые гуру - подскажите, что я не учёл.
Код: (не пугайтесь, я просто учусь  Смеющийся)

Код:
void* fileCopyThread(void* arg)
{
    QPair<QString, QString>* p = (QPair<QString, QString>*)arg;
    QFile::copy(p->first, p->second);
    return NULL;
}

void* dirThread(void* arg)
{
        QPair<QDir, QDir>* temp = (QPair<QDir, QDir>*)arg;


        QFileInfoList list = (*temp).first.entryInfoList();
        for(QFileInfoList::iterator tmp = list.begin();tmp<list.end();tmp++)
        {
                if(((*tmp).fileName() == ".") || ((*tmp).fileName() == "..") || ((*tmp).isSymLink()))continue;

                if((*tmp).isFile() && (*tmp).exists())
                {

                        //Тут файловый поток
                        QPair<QString, QString> f;
                        f.first = (*tmp).absoluteFilePath();
                        f.second = (*temp).second.absolutePath() + "/" + (*tmp).fileName();
                        pthread_t tttt;

                        pthread_create(&tttt, NULL, fileCopyThread, (void*)(&f));
                        pthread_join(tttt, NULL);   //Если ждать - всё ок!
                        //fileCopyThread((void*)(&f));   //Это для проверки в "однопоточном" режиме
                        continue;
                }
                if((*tmp).isDir())
                {
                        //Вот тут рекурсию
                        (*temp).second.mkdir((*tmp).fileName());
                        QPair<QDir, QDir> t;
                        t.first = QDir((*tmp).filePath());
                        t.second = QDir((*temp).second.path() + "/" + (*tmp).fileName());
                        pthread_t tmpt;
                        pthread_create(&tmpt, NULL, dirThread, (void*)(&t));
                        pthread_join(tmpt, NULL);   //Ждём

                        //dirThread((void*)&t);  //Однопоток
                        continue;
                }

        }
        return NULL;
}



int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF8"));

    if(argc<2)
    {
            qDebug()<<"Беда с аргументами";
            return 0;
    }
    QPair<QDir, QDir> p;
    p.first = QDir(argv[1]);
    p.second = QDir(argv[2]);
    pthread_t thr1;
    pthread_create(&thr1, NULL, dirThread, (void*)(&p));
    pthread_join(thr1, NULL);

    return 0;
}
Записан
Rcus
Гость
« Ответ #1 : Сентябрь 29, 2010, 16:48 »

QPair<QString, QString> создается на стеке одного потока, когда другой поток пытается оттуда читать то получает совсем не то что ожидал.
Записан
toggetit
Гость
« Ответ #2 : Сентябрь 29, 2010, 18:02 »

То бишь выделять память в куче?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Сентябрь 30, 2010, 17:59 »

То бишь выделять память в куче?
Да, и поручить удаление запускаемой нитке.

А также:

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

- программировать легко и приятно но только если не нужно отслеживать ошибки и обеспечивать возможность прервать операцию  Улыбающийся

- в этой задаче (как и в очень многих других) нужно сначала получить/установить список решаемых задач, а потом уже распределять их между нитками.

Ну на первое время этого хватит  Улыбающийся
Записан
toggetit
Гость
« Ответ #4 : Октябрь 01, 2010, 09:56 »

Усё. Память выделяю в куче. Нитка освобождает по завершению. Результат тот же - завершается прога на копировании файла. Предполагаю, что QFile::copy не thread-safe. Хотя вероятно, что я не прав

По поводу бесконтрольного размножения потоков - в задаче указано, что по одному потоку на каждый файл и папку, что собственно я и делаю. Или может я чего-то недопонял?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #5 : Октябрь 01, 2010, 10:37 »

Лучше скорее всего будет сделать сразу всего два потока, а не по каждому на файл и директорию!

Один будет проходить по дереву и "выискивать" нужные поддиректории директории/файлы и добавлять их по ходу прохода в очередь на обработку второму потоку. И по завершении прохода поток должен завершиться.

Второй будет собственно копировать то что у него висит в очередии и по опустошению очереди он должен завершиться..

Как то так.

Хотя, поищитут по форуму или спроси у Пантера http://www.prog.org.ru/index.php?action=profile;u=4067 т.к. он реализовывал нечто похожее в своем файловом менеджере http://gitorious.org/panthercommander/mainline/trees/master

См у него реализацию:
Цитировать
qfileoperationsthread.h
qfileoperationsthread.cpp
« Последнее редактирование: Октябрь 01, 2010, 10:53 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Октябрь 01, 2010, 13:09 »

По поводу бесконтрольного размножения потоков - в задаче указано, что по одному потоку на каждый файл и папку, что собственно я и делаю. Или может я чего-то недопонял?
Того что все начинается с разумной постановки задачи  Улыбающийся

Лучше скорее всего будет сделать сразу всего два потока, а не по каждому на файл и директорию!
Это перебор в др. сторону - а если 4 ядра или 8, а мы используем всего 2? В данном случае очередь строится отлично и можно использовать оптимальное число ниток (= число ядер + 1). Лучше сразу избавиться от очевидного но неверного "1 нитка занимается 1 файлом"
Записан
toggetit
Гость
« Ответ #7 : Октябрь 05, 2010, 09:34 »

Лучше скорее всего будет сделать сразу всего два потока, а не по каждому на файл и директорию!

Один будет проходить по дереву и "выискивать" нужные поддиректории директории/файлы и добавлять их по ходу прохода в очередь на обработку второму потоку. И по завершении прохода поток должен завершиться.

Второй будет собственно копировать то что у него висит в очередии и по опустошению очереди он должен завершиться..

Да, согласен, так даже интересней. Тут видится возможность потренироваться в использовании мьютексов
Спасибо
« Последнее редактирование: Октябрь 05, 2010, 09:38 от toggetit » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #8 : Октябрь 05, 2010, 13:14 »

В qt solutions есть класс.
Записан
toggetit
Гость
« Ответ #9 : Октябрь 05, 2010, 15:04 »

В qt solutions есть класс.

Будьте добры, скажите поподробней.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #10 : Октябрь 05, 2010, 17:35 »

http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Widgets/qtcopydialog/
http://doc.qt.nokia.com/solutions/4/qtcopydialog/qtcopydialog.html
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.055 секунд. Запросов: 22.