Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > Распараллеливание процессов Unix


Автор: Alexis777 14.5.2018, 19:00
Добрый день помогите реализовать программу инвертирования содержимого файлов из нескольких подкаталогов (каждый процесс работает со своим файлом) двумя параллельными алгоритмами:

1) с использованием сигналов и очереди сообщений;

2) с использованием семафоров и разделяемой памяти.

Читал теорию, но как делать не понял. Буду рад любой помощи)

Вот теория, если кто захочет помочь) https://ru.files.fm/u/bz5m36xf#_

Саму программу сделал:

Код


#include <iostream>

#include <fstream>

#include <algorithm>

#include <iterator>

#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;



void reverseFile(fs::path pfile, fs::path const& pdir)

{

    std::fstream ifs(pfile, std::ios::in), ofs(pdir / pfile.filename(), std::ios::out);

    if (ifs.is_open() && ofs.is_open())

    {

        std::string str{ std::istreambuf_iterator<char>{ifs.rdbuf()}, {} };

        std::reverse_copy(str.begin(), str.end(), std::ostreambuf_iterator<char>(ofs));

    }

    else

    {

        std::cerr << "Unable to open file(s): " << pfile << "  " << pdir / pfile.filename() << "\n\n";

    }

    ifs.close();

    ofs.close();

}



// создаём путь папки в каталоге с инвертированными файлами

fs::path newPath(fs::path const& oldPth, fs::path const& pd1, fs::path const& pd2)

{

    fs::path ret = pd2;

    auto pr = std::mismatch(oldPth.begin(), oldPth.end(), pd1.begin(), pd1.end());



    for (auto ib(pr.first), ie(oldPth.end()); ib != ie; ++ib)

    {

        ret /= *ib;

    }



    return ret;

}



int main()

{

    try

    {

        fs::path pd1("C:\\dir1"); // каталог с исходными файлами

        fs::path pd2("C:\\dir2"); // каталог с инвертированными файлами

        if (!fs::exists(pd2))

        {

            fs::create_directories(pd2); // может кинуть исключение

        }

        for (fs::recursive_directory_iterator ib(pd1), ie; ib != ie; ++ib) // перебираем все файлы в dir 1

        {

            if (fs::is_regular_file(ib->path())) // инвертируем каждый файл

            {

                reverseFile(ib->path(), newPath(ib->path(), pd1, pd2));

            }

            else if (fs::is_directory(ib->path())) // создаём папку в каталоге с инвертированными файлами

            {

                fs::create_directory(newPath(ib->path(), pd1, pd2));

            }

        }

    }

    catch (std::exception const& exc)

    {

        std::cerr << "Exception: " << exc.what() << std::endl;

    }

}





Также есть с потоками реализация делал:

Код
#include <iostream>

#include <fstream>

#include <list>

#include <pthread.h>

#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;



pthread_mutex_t mtxCerr;



struct var

{

    var(fs::path const& pf1, fs::path const& pf2) : pfile1(pf1), pfile2(pf2){};

    fs::path pfile1;

    fs::path pfile2;

};



void* reverseFile(void* arg)

{

    fs::path pfile1(reinterpret_cast<var*>(arg)->pfile1);

    fs::path pfile2(reinterpret_cast<var*>(arg)->pfile2);

    std::fstream ifs(pfile1, std::ios::in | std::ios::binary), ofs(pfile2, std::ios::out | std::ios::binary);

    if (ifs.is_open() && ofs.is_open())

    {

        ifs.seekg(0, ifs.end);

        if (ifs.tellg() >= std::streampos(1))

        {

            for (ifs.seekg(-1, ifs.cur); ; ifs.seekg(-2, ifs.cur))

            {

                char c = ifs.get();

                //std::cout << int(c) << "  ";

                ofs.put(c);

                if (ifs.tellg() == std::streampos(1))

                {

                    break;

                }

            }

        }

    }

    else

    {

        pthread_mutex_lock(&mtxCerr);

        std::cerr << "Unable to open file(s): " << pfile1 << "  " << pfile2 << "\n\n";

        pthread_mutex_unlock(&mtxCerr);

    }

    ifs.close();

    ofs.close();



    pthread_exit(0);

}



fs::path newPath(fs::path const& oldPth, fs::path const& pd1, fs::path const& pd2)

{

    fs::path ret = pd2;

    auto pr = std::mismatch(oldPth.begin(), oldPth.end(), pd1.begin());



    for (auto ib(pr.first), ie(oldPth.end()); ib != ie; ++ib)

    {

        ret /= *ib;

    }



    return ret;

}



int main()

{

    try

    {

        fs::path pd1("/home/user/student/dir1"); // каталог с исходными файлами

        fs::path pd2("/home/user/student/dir2/ddd"); // каталог с инвертированными файлами



        pthread_mutex_init(&mtxCerr, nullptr);



        if (!fs::exists(pd2))

        {

            fs::create_directories(pd2); // может кинуть исключение

        }



        std::list<pthread_t> lt;

        std::list<var> la;

        for (fs::recursive_directory_iterator ib(pd1), ie; ib != ie; ++ib) // перебираем все файлы в dir 1

        {

            if (fs::is_regular_file(ib->path())) // инвертируем каждый файл

            {

                lt.emplace_back();

                la.emplace_back(ib->path(), newPath(ib->path(), pd1, pd2));

                pthread_create(&lt.back(), nullptr, reverseFile, &la.back());

            }

            else if(fs::is_directory(ib->path()))

            {

                fs::create_directory(newPath(ib->path(), pd1, pd2));

            }

        }

        for(auto& thr : lt)

        {

            pthread_join(thr, nullptr);

        }

        pthread_mutex_destroy(&mtxCerr);

    }

    catch (std::exception const& exc)

    {

        std::cerr << "Exception: " << exc.what() << std::endl;

    }

}


Всем заранее спасибо за помощь)

Автор: xvr 15.5.2018, 12:38
У вас напрашивается такая структура программы:
  • При старте программа создаёт канал обмена информацией, по которому она будет передавать имена файлов которые надо инвертировать
  • Затем она стартует (через fork) несколько обработчиков, которые и будут инвертировать файлы
  • Затем она сканирует директории и отправляет именя файлов в канал (читать их оттуда будут обработчики)
  • По окончании она отправляет в канал несколько специальных сообщений EOW (по числу обработчиков)
  • Ждёт завершания всех обработчиков и завершается сама
Обработчик делает следующее:
  • Читает из канала (в блокирующем режиме) имя файла и инвертирует его
  • Если вместо имени файла пришло EOW - завершается
Канал обмена может быть строен 2 путями (по вашему заданию):
  • Очередь сообщений, в которую пушат сообщения с именем файла (или сообщение например нулевой длинны для обозначения EOW). Куда тут ещё пристегнуть сигналы - непонятно.
  • Кусок разделяемой памяти, в которой лежит очередь с именами файлов в виде массива с указателями чтения и записи (классический кольцевой буфер). Что бы параллельно работающие процессы не порубали его в капусту доступ ограничивается семафором, работающим в режиме мьютекса - даёт доступ только 1 процессу за раз.
Собственно всё

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)