LINUX.ORG.RU

cpp-worker с расшаренным ресурсом для GUI как?

 , ,


0

1

Требуется на C++ (std::*) написать модуль worker.cpp (затем библиотеку) - Worker и Share. Worker в отдельном потоке выполняет некоторые расчеты и в ходе работы записывает текущий результат в Share. Предназначен этот модуль для запуска в основном потоке GUI-приложения, при этом из из методов GUI приложения производится чтение и отображение содержимого Share.

Попробовал в методе run() Worker создать поток, запустить вычисления и обновлять ресурс с блокировкой. Но, при этом запуск run() блокирует графический интерфейс. Графический интерфейс разблокируется только после завершения run().

Помогите правильно организовать поток и блокировки. Поток нужно запускать в модуле worker.cpp, а не из GUI. Разработчик GUI знает только о методах чтения из структуры Share и не заботится об организации многопоточности и блокировок.

struct Share {
    int data;
    std::mutex locker;
};


class Worker {
public:
    Worker(Share *sharePtr);
    ~Worker();
    void run();

private:
    Share* sharePtr;
    void worker();
};

Worker::Worker(Share* shrPtr): sharePtr(shrPtr) {}

Worker::~Worker(){}

void Worker::run() {
    std::thread t(&Worker::worker, this);
    t.join();
}

void Worker::worker() {
    int i = 0;
    while (i<999) {
        std::unique_lock<std::mutex> lock(sharePtr->locker);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        sharePtr->data = rand();
	++i;
    }
    sharePtr->data = 555;
}

Проверка на примере Qt:

class MainWindow: public QWidget 
{
    Q_OBJECT

    public:
        MainWindow(QWidget *parent = nullptr);
         ~MainWindow();
        void initUI();

    public slots:
        void Work();
        void updateLabel();

    private:
        QLabel *info;
        QPushButton *push;
	QVBoxLayout *vLayout;
        QTimer *tmr;

	Share currentShare;

};

mainWindow::MainWindow(QWidget *parent): QWidget(parent){
    initUI();
    connect(push, SIGNAL(clicked()), this, SLOT(Work()));

    tmr = new QTimer();
    tmr->setInterval(100); 
    connect(tmr, SIGNAL(timeout()), this, SLOT(updateLabel()));
    tmr->start();
}

MainWindow::~MainWindow(){
    delete tmr;
}

void MainWindow::initUI(){
    vLayout = new QVBoxLayout(this);
    info = new QLabel("-_-");
    push = new QPushButton("push");
    vLayout->addWidget(info);
    vLayout->addWidget(push);
}

void MainWindow::Work(){
	Worker worker(&currentShare);
	worker.run();
}

void MainWindow::updateLabel(){
    std::unique_lock<std::mutex>  lock(currentShare.locker);
    info->setText( QString::number( currentShare.data ) );
}

Спроси у препода зачем это нужно, и как это делать.

У тебя тут join происходит, поэтому UI поток и блочится:

void Worker::run() {
    std::thread t(&Worker::worker, this);
    t.join();
}

Нормально делать нужно как-то так(код в IDE не запускал, писал прямо на лоре, если где опечатался, то исправишь сам):

// удаляем timer, мы и так знаем когда вызывать updateLabel()
// делаем наш класс Worker тоже QObject, чтобы появился слот
// deleteLater и мы могли emit сигнал doneProcess в конце метода 
// worker
void MainWindow::Work(){
    QThread* workerThread = nullptr;
    MyWorker* workerObject = nullptr;

    try {
        workerThread = new QThread;
        workerObject = new MyWorker(&currentShare);
    } catch (const std::exception& e) {
        if (workerThread != nullptr) {
            delete workerThread;
        }
        if (workerObject!= nullptr) {
            delete workerObject;
        }
        throw e;
    }

    connect(workerThread, &QThread::started, workerObject, &MyWorker::worker);
    connect(workerObject, &MyWorker::doneProcess, workerThread, &QThread::quit);
    connect(workerObject, &MyWorker::doneProcess, workerObject, &MyWorker::deleteLater);
    connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
    connect(workerThread, &QThread::finished, this, &MainWindow::updateLabel);

    workerThread->start();
}
fsb4000 ★★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 1)

1. увеличить время жизни t и прикрепить

void Worker::run() {
    t = new std::thread(&Worker::worker, this);
    t->detach();
}

2. увеличить время жизни worker, предусмотреть остановку работающего потока при вызове деструктора ~MainWindow.

cvm4t ()

Я бы подумала об использовании промисов.

Liz812 ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.