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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Не отрабатывает сигнал если для синхронизации используется мьютекс  (Прочитано 5662 раз)
Roman
Гость
« : Июнь 17, 2016, 00:58 »

Привет всем.
В своем рабочем проекте я столкнулся с тем, что посланный сигнал не доходит до получателя. Есть два потока и один из по завершении некоторой работы сообщает второму об этом. Все хорошо было до тех пор, пока я не стал использовать мьютексы для дополнительный синхронизации. Теперь я понимаю, что проблема была прежде всего в дизайне. Но если не брать это в расчет хотелось все же понять что неправильно и что является источником проблемы. Я написал тестовый проект, который в общем показывает суть проблемы.
Код:
#ifndef TESTCLASSES_H
#define TESTCLASSES_H

#include <QtTest/QTest>
#include<QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>

class Worker :public QObject
{
        Q_OBJECT
public:
    QMutex _mut;

    void init()
    {
        qDebug() << "Worker::init - lock mutex";
        _mut.lock();
    }
public slots:
    void process()
    {
        qDebug() << "Worker::process - trying to lock mutex";
        QMutexLocker m(&_mut);
        qDebug() << "Worker::process - mutex has been released ";
    }
    void releasemutex()
    {
        qDebug() << "Worker::releasemutex - unlock mutex";
        _mut.unlock();
    }

};

class Finisher :public QObject
{
        Q_OBJECT

public slots:
    void process()
    {
        qDebug() << "Finisher::process - start sleeping";
        QTest::qSleep(2000);
        qDebug() << "Finisher::process - end sleeping,emit finished";
        emit finished();
    }

signals:
    void finished();
};

class Controller :public QObject
{
    Q_OBJECT

    Worker worker;
    Finisher finisher;
    QThread wThread;
    QThread fThread;

public:

    void init()
    {
        qDebug() << "Controller::init start";

        connect(&finisher, SIGNAL(finished()), &worker, SLOT(releasemutex()));
        worker.init();

        worker.moveToThread(&wThread);
        finisher.moveToThread(&fThread);

        connect(&fThread, SIGNAL(started()), &finisher, SLOT(process()));
        connect(&wThread, SIGNAL(started()), &worker, SLOT(process()));
        connect(&fThread, SIGNAL(finished()), &finisher, SLOT(deleteLater()));
        connect(&wThread, SIGNAL(finished()), &finisher, SLOT(deleteLater()));

        wThread.start();
        fThread.start();

        qDebug() << "Controller::init end";
    }
};

#endif // TESTCLASSES_H

#include <QCoreApplication>
#include "TestClasses.h"

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

    Controller controller;
    controller.init();

    return a.exec();
}


Если убрать мьютекс то все окей. Я не понимаю почему он лочит процесс Worker . Ведь поток Finisher  посылает сигнал finished, что по идее дергает метод releasemutex
Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #1 : Июнь 17, 2016, 01:13 »

потому что у тебя слот releasemutex пытается вызваться в контексте event loop'а заблокированного потока. Если переписать строчку
Код
C++ (Qt)
connect(&finisher, SIGNAL(finished()), &worker, SLOT(releasemutex()));
 
на
Код
C++ (Qt)
connect(&finisher, SIGNAL(finished()), &worker, SLOT(releasemutex()), Qt::DirectConnection);
 
то будет ожидаемое тобой поведение.
Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июнь 17, 2016, 14:46 »

то будет ожидаемое тобой поведение.
А чего это мутекс захваченный одной ниткой освобождается другой? Так нельзя

Код:
    void init()
    {
        qDebug() << "Worker::init - lock mutex";
        _mut.lock();
    }
public slots:
    void process()
    {
        qDebug() << "Worker::process - trying to lock mutex";
        QMutexLocker m(&_mut);
Нитка захватила мутекс в init, а потом опять пытается его захватить - нельзя, по умолчанию мутекс не рекурсивный 
Записан
Roman
Гость
« Ответ #3 : Июнь 20, 2016, 13:03 »

А почему нельзя? Я новичек в задачах синхронизации, почему нельзя освобождать мьютекс из другого потока?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июнь 20, 2016, 13:40 »

А почему нельзя? Я новичек в задачах синхронизации, почему нельзя освобождать мьютекс из другого потока?
Потому что данный примитив синхронизации устроен так: освободить мутекс может (и должен) только тот кто его захватил. Если же требуется освобождать из другой нитки - используйте др примитив QSemaphore, вот для него пожалуйста
« Последнее редактирование: Июнь 20, 2016, 13:48 от Igors » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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