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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Поиск слов в файле в Qt(Mutex)  (Прочитано 10149 раз)
stasJun
Гость
« : Октябрь 03, 2016, 12:11 »

Мне нужно написать консольную программу:
Которая для заданного каталога файлов на диске находит файлы, содержащие заданное слово с использованием многопоточности. Программа должна вывести в столбик имена найденных файлов в алфавитном порядке.
Я сделал програму  но нужно ее  было  еще переделать и сделать с Mutexом, и я  не  знаю правильно  ли я  сделал с ним. Посмотрите и скажите  верно ли все
Хедер:
Код:
#ifndef FIND_WORD_IN_FILE_THREAD_H
#define FIND_WORD_IN_FILE_THREAD_H
 
#include <QThread>
#include <QString>
#include <QtDebug>
#include <QMutex>
 
class FindWordInFileThread : public QThread
{
public:
    FindWordInFileThread(const std::vector<QString>& filePath, const QString& word, size_t startIndex, size_t numElements, std::vector<QString>& foundFiles, QMutex* mutex);
    virtual void run();
 
private:
    const std::vector<QString>& mFilePath;
    const QString mWord;
    size_t mStartIndex;
    size_t mNumElements;
    std::vector<QString>& mFoundFiles;
    QMutex* mMutex;
};
 
#endif // FIND_WORD_IN_FILE_THREAD_H
CPP:
Код:
#include "FindWordInFileThread.h"
 
#include <QFile>
#include <QTextStream>
#include <QFileInfo>
#include <QMutexLocker>
 
FindWordInFileThread::FindWordInFileThread(const std::vector<QString>& filePath, const QString& word, size_t startIndex, size_t numElements, std::vector<QString>& foundFiles, QMutex* mutex)
    : mFilePath(filePath)
    , mWord(word)
    , mStartIndex(startIndex)
    , mNumElements(numElements)
    , mFoundFiles(foundFiles)
    , mMutex(mutex)
{}
 
void FindWordInFileThread::run()
{
    for (size_t index = mStartIndex; index < mStartIndex + mNumElements; ++index)
    {
        QFile file(mFilePath[index]);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            return;
 
        QTextStream textStream(&file);
        while (!textStream.atEnd())
        {
            QString line = textStream.readLine();
            QMutexLocker locker(mMutex);
            if (line.contains(mWord, Qt::CaseInsensitive))
            {
                mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName());
                break;
            }
        }
        file.close();
    }
}
Main:
Код:
void FindWordInFiles(const QString& word, const size_t numThreads)
{
    QMutex mutex;
 
    QTime time(QTime::currentTime());
    std::srand(time.msecsSinceStartOfDay());
 
    std::vector<QThread*> threads;
    threads.reserve(numThreads);
 
    QDirIterator dirIt("D:/11", QDirIterator::Subdirectories);
 
    std::vector<QString> paths;
    while (dirIt.hasNext())
    {
        dirIt.next();
        if (QFileInfo(dirIt.filePath()).isFile())
        {
            if (QFileInfo(dirIt.filePath()).suffix() == "txt")
                paths.push_back(dirIt.filePath());
        }
    }
 
    const std::vector<Range> ranges = GenerateRanges(numThreads, paths.size());
    std::vector<QString> foundFiles;
 
    time.start();
    for (size_t index = 0; index < numThreads; ++index)
        threads.push_back(new FindWordInFileThread(paths, word, ranges[index].mStart, ranges[index].mLength, foundFiles, &mutex));
 
    for (size_t index = 0; index < numThreads; ++index)
        threads[index]->start();
 
    for (size_t index = 0; index < numThreads; ++index)
        threads[index]->wait();
    const int elapsedMs = time.elapsed();
 
    std::sort(foundFiles.begin(), foundFiles.end());
 
    qDebug() << "Elapsed time(ms): " << elapsedMs;
    for (size_t index  = 0; index < foundFiles.size(); ++index)
        qDebug() << foundFiles[index];
 
    for (size_t index = 0; index < numThreads; ++index)
        delete threads[index];
}
 
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    const int idealThreadCount = QThread::idealThreadCount();
 
    qDebug() << "One Thread:";
    FindWordInFiles("pavlik", 1);
    qDebug() << "";
 
    qDebug() << "Two Thread:";
    FindWordInFiles("pavlik", 2);
    qDebug() << "";
 
    qDebug() << "Optimal Thread: ";
    qDebug() <<"Ideal Thread Count:" << idealThreadCount;
    FindWordInFiles("pavlik", idealThreadCount);
    qDebug() << "";
 
    qDebug() << "Twenty Thread: ";
    FindWordInFiles("pavlik", 20);
 
    return app.exec();
}
« Последнее редактирование: Октябрь 03, 2016, 12:13 от stasJun » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Октябрь 03, 2016, 12:40 »

Код:
   
            QString line = textStream.readLine();
            QMutexLocker locker(mMutex);
            if (line.contains(mWord, Qt::CaseInsensitive))
            {
                mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName());
                break;
            }
        }
}
Файлы у Вас не пересекаются, поэтому лучше захватывать мутекс если сработал if (перед mFoundFiles.push_back). Ну и многовато аргументов в конструкторе, напрашивается структура. А так вполне грамотно
Записан
stasJun
Гость
« Ответ #2 : Октябрь 03, 2016, 13:40 »

Код:
   
            QString line = textStream.readLine();
            QMutexLocker locker(mMutex);
            if (line.contains(mWord, Qt::CaseInsensitive))
            {
                mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName());
                break;
            }
        }
}
Файлы у Вас не пересекаются, поэтому лучше захватывать мутекс если сработал if (перед mFoundFiles.push_back). Ну и многовато аргументов в конструкторе, напрашивается структура. А так вполне грамотно
так вы имели введу?
Код:
void FindWordInFileThread::run()
{
    for (size_t index = mStartIndex; index < mStartIndex + mNumElements; ++index)
    {
        QFile file(mFilePath[index]);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            return;

        QTextStream textStream(&file);
        while (!textStream.atEnd())
        {
            QString line = textStream.readLine();
            if (line.contains(mWord, Qt::CaseInsensitive))
            {
                QMutexLocker locker(mMutex);
                mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName());
                break;
            }
        }
        file.close();
    }
}

Записан
qate
Супер
******
Offline Offline

Сообщений: 1175


Просмотр профиля
« Ответ #3 : Октябрь 03, 2016, 16:48 »

не пойму зачем тут mutex
есть список файлов - их можно отдать на поиск слова каждому потоку (что может быть не эффективно по чтению диска)
или отдавать прочитанные данные каждому потоку через Qt Concurrent
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4349



Просмотр профиля
« Ответ #4 : Октябрь 03, 2016, 16:57 »

не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков.
Записан
stasJun
Гость
« Ответ #5 : Октябрь 03, 2016, 21:45 »

не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков.
да вы правы,  тут  мы  гарантируемо и контролиюем  нормальную  работу с файлом foundFiles.
У меня норально и правильно работает код?
Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #6 : Октябрь 03, 2016, 23:36 »

не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков.
При использовании QtConcurrent не нужен же. Результат и так в основной поток попадет.
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
stasJun
Гость
« Ответ #7 : Октябрь 03, 2016, 23:52 »

не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков.
При использовании QtConcurrent не нужен же. Результат и так в основной поток попадет.
не  буду спорить. но! я  не использую QtConcurrent. А использую Mutex. И попросил посмотреть правильно  ли использую) А мне  без обид только 1 пост  по теме  ответили, все остальное флуд,  да полезный  флуд, буду  знать что есть QtConcurrent,  но увы   к моему  вопросу  не относиться.
Записан
stasJun
Гость
« Ответ #8 : Октябрь 05, 2016, 20:37 »

Теперь мне нужно вместо консоли сделать  в виде виджетта.
1)Подскажите  как в виджетте директорию задавать?
2) Как сделать что бы в  нижней  результат выводить(туда вставлять  результат поиска)?

Спасибо

Что я  уже сделал:
хедер:
Код:
#ifndef FINDWORDINFILETHREAD_H
#define FINDWORDINFILETHREAD_H

#include <QtWidgets>

class FindWordInFileThread : public QWidget
{
    Q_OBJECT

public:
    FindWordInFileThread(QWidget *parent = 0);
    ~FindWordInFileThread();
public slots:
    void start();

private:
    int mStart;
};

#endif // FINDWORDINFILETHREAD_H
СПП:
Код:
#include "FindWordInFileThread.h"

FindWordInFileThread::FindWordInFileThread(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("Find word in file thread");
    QLabel* selectDirectory = new QLabel("Select directory:");
    QPushButton* start = new QPushButton("&Start");
    connect(start, SIGNAL(clicked()), SLOT(start()));

    QLineEdit* text = new QLineEdit;

    QVBoxLayout* layout = new QVBoxLayout;
    layout->addWidget(selectDirectory);
    layout->addWidget(start);
    layout->addWidget(text);
    setLayout(layout);
    resize(500, 300);
}
void FindWordInFileThread::start()
{

}

FindWordInFileThread::~FindWordInFileThread()
{

}
меин:
Код:
#include "FindWordInFileThread.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    FindWordInFileThread findWordInFileThread;
    findWordInFileThread.show();

    return app.exec();
}
« Последнее редактирование: Октябрь 05, 2016, 21:19 от stasJun » Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #9 : Октябрь 05, 2016, 21:29 »

Теперь мне нужно вместо консоли сделать  в виде виджетта.
1)Подскажите  как в виджетте директорию задавать?
2) Как сделать что бы в верхней части  о задавать  директорию а в  нижней  результат выводить?
Если с точки зрения "дизайна", то я бы сделал примерно так:

В нижнем QGroupBox находиться QListWidet. Можно заменить на QTextEdit.
Ну и вместо ручного кодирования использовал бы дизайнер. Или по условию задачи нужно ручками виджеты на форме выставлять? Если да, то использовал бы сгенереный дизайнером код с небольшими правками =)


Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4349



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

Я бы еще lineedit добавил для ввода искомого слова. Может оказаться полезным. Улыбающийся
Записан
stasJun
Гость
« Ответ #11 : Октябрь 05, 2016, 22:43 »

Теперь мне нужно вместо консоли сделать  в виде виджетта.
1)Подскажите  как в виджетте директорию задавать?
2) Как сделать что бы в верхней части  о задавать  директорию а в  нижней  результат выводить?
Если с точки зрения "дизайна", то я бы сделал примерно так:

В нижнем QGroupBox находиться QListWidet. Можно заменить на QTextEdit.
Ну и вместо ручного кодирования использовал бы дизайнер. Или по условию задачи нужно ручками виджеты на форме выставлять? Если да, то использовал бы сгенереный дизайнером код с небольшими правками =)




а скиньте код как вы сделали виджет,  да нужно  ручками  самому  делать
Записан
stasJun
Гость
« Ответ #12 : Октябрь 06, 2016, 10:34 »

Я бы еще lineedit добавил для ввода искомого слова. Может оказаться полезным. Улыбающийся
я сделал  так  открытие  директории:
Код:
QString str = QFileDialog::getExistingDirectory(0, "Directory Dialog", "");
но как мне сделать  так как  на картинке в  Kurles ?

я про это говорю(как  на фото)
« Последнее редактирование: Октябрь 06, 2016, 11:49 от stasJun » Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



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

а скиньте код как вы сделали виджет,  да нужно  ручками  самому  делать
Код
C++ (Qt)
CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
{
 
   /* нужные указатели, такие как toolButtonSelectDir,
    * pushButtonStart, lineEditDirName и listWidgetResult
    * можно (нужно) сдеалать переменными класса */

   QVBoxLayout *verticalLayout2;
   QHBoxLayout *horizontalLayout2;
   QGroupBox *groupBox;
   QHBoxLayout *horizontalLayout;
   QLineEdit *lineEditDirName;
   QToolButton *toolButtonSelectDir;
   QPushButton *pushButtonStart;
   QGroupBox *groupBox2;
   QVBoxLayout *verticalLayout;
   QListWidget *listWidgetResult;
 
   verticalLayout2 = new QVBoxLayout(this);
   verticalLayout2->setSpacing(6);
   verticalLayout2->setContentsMargins(11, 11, 11, 11);
   horizontalLayout2 = new QHBoxLayout();
   horizontalLayout2->setSpacing(6);
   groupBox = new QGroupBox(this);
 
   horizontalLayout = new QHBoxLayout(groupBox);
   horizontalLayout->setSpacing(6);
   horizontalLayout->setContentsMargins(11, 11, 11, 11);
 
   lineEditDirName = new QLineEdit(groupBox);
 
 
   horizontalLayout->addWidget(lineEditDirName);
 
   toolButtonSelectDir = new QToolButton(groupBox);
 
   horizontalLayout->addWidget(toolButtonSelectDir);
 
 
   horizontalLayout2->addWidget(groupBox);
 
   pushButtonStart = new QPushButton(this);
 
   horizontalLayout2->addWidget(pushButtonStart);
 
 
   verticalLayout2->addLayout(horizontalLayout2);
 
   groupBox2 = new QGroupBox(this);
 
   verticalLayout = new QVBoxLayout(groupBox2);
   verticalLayout->setSpacing(6);
   verticalLayout->setContentsMargins(11, 11, 11, 11);
 
   listWidgetResult = new QListWidget(groupBox2);
 
   verticalLayout->addWidget(listWidgetResult);
 
 
   verticalLayout2->addWidget(groupBox2);
 
   setWindowTitle(tr("Поиск файла"));
   toolButtonSelectDir->setText("...");
   pushButtonStart->setText(tr("Начать"));
   lineEditDirName->setText(tr("d:/some_dir"));
   resize(600, 600);
}
Код, сгенеренный uic'ом, и немного подправленный.
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
stasJun
Гость
« Ответ #14 : Октябрь 06, 2016, 15:57 »

у вас в  коде  нигде не пишеться: Выбор директории и результат поиска
я сделал))
Код:
QGroupBox* groupBoxFirst = new QGroupBox("&Select directory:");
    QGroupBox* groupBoxSecond = new QGroupBox("&Result found:");
« Последнее редактирование: Октябрь 06, 2016, 16:13 от stasJun » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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