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

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

Страниц: 1 ... 5 6 [7] 8   Вниз
  Печать  
Автор Тема: Очереди, самодельные сигналы  (Прочитано 47978 раз)
BRE
Гость
« Ответ #90 : Август 19, 2010, 18:36 »

Встроил дибаг-сообщения в отправителя сигнала, получателя сигнала и потока. Получатель сигнала (слот) определён в классе QThread, отправитель в главном потоке, DirectConnection не использую. Почемуто номера потоков отправителя и получателя совпадают.
Без исходников трудно сказать, но как мне кажется ты не учел, что сам объект QThread создается в контексте создающего потока.
Посмотри на:
void QObject::moveToThread ( QThread * targetThread )

А лучше покажи свой пример, так будет проще все исправить.
Записан
labview
Гость
« Ответ #91 : Август 19, 2010, 18:43 »

Да, QThread создаётся в main.cpp(а где ему ещё создаваться?), и отправитель сигнала тоже относится к главному потоку.

Мув посмотрю, спасибо.

Код находится здесь:
http://www.prog.org.ru/index.php?topic=14556.msg95023#msg95023
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11213


Просмотр профиля
« Ответ #92 : Август 19, 2010, 20:09 »

На вопрос обработки сигнала в run() я ответа не получил. Получается если в слоте/слотах я выполняю действия с обьектом, то зачем мне нужен run()?
Как уже подробно обсуждалось в этой теме, Вы можете просто построить все на слот/сигнал (обмен через eventLoop), или перекрыть run и сделать свою очередь. Или даже использовать и то и другое (вычурно но возможно).

Я хотел чтобы обьект (как и реальный) жил своей жизнью (параллельно к другим), но если от обьекта ничего не требуется, то и спал бы себе.
...
Такой вопрос: если файл с траекторией очень большой (например 1 гиг), то зачем мне держать его в памяти?
В памяти или читать с диска - не суть. Чтение траектории не выглядит тем что "может жить своей жизнью". Вот если бы Вы такие запросы получали от 2 и более ниток - имело бы смысл делать это параллельно с др. операциями. А если все равно "блок алгоритм" ждет - чего без толку плодить нитки?

Да, QThread создаётся в main.cpp(а где ему ещё создаваться?), и отправитель сигнала тоже относится к главному потоку.
А как connect создавали? Указали тип QueuedConnection?
Записан
labview
Гость
« Ответ #93 : Август 19, 2010, 20:14 »

В памяти или читать с диска - не суть. Чтение траектории не выглядит тем что "может жить своей жизнью". Вот если бы Вы такие запросы получали от 2 и более ниток - имело бы смысл делать это параллельно с др. операциями. А если все равно "блок алгоритм" ждет - чего без толку плодить нитки?
С этим согласен, я был не согласен с тем, чтобы считать всю траекторию в память.

А как connect создавали? Указали тип QueuedConnection?
Пробовал Auto, Queued и Direct, всё один результат.
Записан
labview
Гость
« Ответ #94 : Август 19, 2010, 20:54 »

Хотелось бы добить идею со своим листом, а не с сигналами и слотами. Сделал вот так:

Код:
#include "Tasking.h"

Tasking::Tasking()
{
}

Tasking::~Tasking()
{

}

task Tasking::getTask()
{
    while(taskList.empty())
        cond.wait(&mutex, ULONG_MAX);

    mutex.lock();
    task currentTask = taskList.takeFirst();
    mutex.unlock();

    return currentTask;
}

void Tasking::addTask(task newTask)
{
    mutex.lock();
    taskList.append(newTask);
    mutex.unlock();
    cond.wakeOne();
}

Но при запуске проги получаю вот такую ошибку:

Код:
Starte D:\C++\Tasking-build-desktop\debug\Tasking.exe...
ASSERT failure in QMutex::unlock(): "A mutex must be unlocked in the same thread that locked it.", file thread\qmutex.cpp, line 371
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
D:\C++\Tasking-build-desktop\debug\Tasking.exe beendet, Rückgabewert 3

Что не так с мьютексом? С помощью него я хотел защитить обращение (запись/чтение) к QList.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11213


Просмотр профиля
« Ответ #95 : Август 19, 2010, 21:02 »

Что не так с мьютексом? С помощью него я хотел защитить обращение (запись/чтение) к QList.
http://www.prog.org.ru/index.php?topic=14426.msg95492#msg95492
Записан
labview
Гость
« Ответ #96 : Август 19, 2010, 21:16 »

Спасибо, теперь не ругается. А можно узнать почему? Пожалуйста.
Записан
BRE
Гость
« Ответ #97 : Август 19, 2010, 21:43 »

Спасибо, теперь не ругается. А можно узнать почему? Пожалуйста.
Доступ к общим данным должен быть защищен.
Смотри что может произойти если ее не защитить:
управление получает первый поток и успевает выполнить проверку, что в очереди есть задания, после этого планировщик переключается на такой же поток, он успевает проверить, что в очереди есть данные и достать оттуда единственное значение. Сейчас очередь уже пуста, происходит переключение обратно на первый поток, он уже выполнил проверку на то, что в очереди есть задания и бросается его доставать, но очередь уже пуста.
Поэтому, даже чтение количества заданий должно быть защищено.

Почему происходила ошибка. Алгоритм работы условных переменных (QWaitCondition) сводится к тому, что вначале мы запираем мьютекс блокирующий данные, проверяем наличие данных, если в нем есть данные, то мы получаем к нему доступ (заметь, запертый мьютекс будет блокировать попытки других потоков добраться до этих данных), а если данных нет - то мы вызываем wait условной переменной связанной с этим мьютексом (указатель на него мы передаем в параметрах wait), wait открывает этот мьютекс (давая возможность другому потоку записать данные) и усыпляет поток.
Другой поток записывает данные и вызывает wakeOne/wakeAll, чем пробуждает поток(и) ждущие в wait. После пробуждения потока, в функции wait блокируется мьютекс и происходит выход из нее.

P.S. Разберись с QMutexLocker, подобные классы значительно облегчают работу с мьютексами и избавляют от ошибок.
« Последнее редактирование: Август 19, 2010, 21:48 от BRE » Записан
labview
Гость
« Ответ #98 : Август 19, 2010, 22:33 »

Благодарю за разяснение, пока сделал так:

Код:
task Tasking::getTask()
{
    QMutexLocker locker(&mutex);
    while(taskList.empty())
        cond.wait(&mutex, ULONG_MAX);

    return taskList.takeFirst();
}

void Tasking::addTask(task newTask)
{
    QMutexLocker locker(&mutex);
    taskList.append(newTask);
    cond.wakeOne();
}

ЗЫ с ответами какашко получилось, сори, я стёр свой предыдущий ответ.
« Последнее редактирование: Август 19, 2010, 22:35 от labview » Записан
labview
Гость
« Ответ #99 : Август 23, 2010, 16:06 »

Привет!

Появилась новая проблема. Сначала я запускал в main два потока и потом QApplication::exec(). Но ивенты не обрабатывались и окно не прорисовывалось, т.к. QApplication::exec() был блокирован двумя потоками. Немного поразмыслив, я решил запустить третью нить, в функции run() которой, я собирался выполнить QApplication::exec(), то есть запустить главный поток параллельно двум другим.
При старте прога зависает и пишет QApplication::exec: Must be called from the main thread.

А как же мне ещё сделать обработку параллельно?

Выкладываю main.cpp

Код:
#include <QList>

#include "mainwidget.h"
#include "Tasking.h"
#include "guithread.h"
#include "thread1.h"
#include "thread2.h"

int main(int argc, char *argv[])
{
    QList<Tasking*> allTasks;

    Tasking *tasking1 = new Tasking;
    Tasking *tasking2 = new Tasking;
    allTasks.append(tasking1);
    allTasks.append(tasking2);

    GUIThread guiThread(allTasks, argc, argv);
    Thread1 myThread1(allTasks);
    Thread2 myThread2(allTasks);

    QObject::connect(&myThread1, SIGNAL(showData(QString)), guiThread.w, SLOT(addText(QString)));
    QObject::connect(&myThread2, SIGNAL(showData(QString)), guiThread.w, SLOT(addText(QString)));

    guiThread.start();
    myThread1.start();
    myThread2.start();
    guiThread.wait();
    myThread1.wait();
    myThread2.wait();

    return 0;
}

guithread.cpp

Код:
#include "guithread.h"

GUIThread::GUIThread(const QList<Tasking*>& allTasks, int argc, char *argv[])
{
    Tasks = allTasks;
    qapp = new QApplication(argc, argv);
    w = new MainWidget(Tasks);
    w->showMW();
}

void GUIThread::run()
{
    qapp->exec();
}


Ну и на всякий случай код потока (второй сделан аналогично)

Код:
#include "thread1.h"

Thread1::Thread1(const QList<Tasking*>& allTasks)
{
    Tasks = allTasks;
}

void Thread1::run()
{
    task myTask;
    bool exit = FALSE;
    while(!exit)
    {
        myTask = Tasks[0]->getTask();
        switch (myTask.tasknum)
        {
            case 0:
                exit = TRUE;
            case 1:
                emit showData(myTask.data);
                Tasks[1]->addTask(myTask);
        }
    }
}

Спасибо!
Записан
BRE
Гость
« Ответ #100 : Август 23, 2010, 16:32 »

QApplication::exec: Must be called from the main thread
это обязательное условие. Нельзя работать с GUI в других потоках, только главный.
Вызывай exec() в функции main().

А вот ожидать завершения дочерних потоков после старта не нужно (убери вызовы wait()).
Записан
labview
Гость
« Ответ #101 : Август 23, 2010, 16:38 »

Спасибо, Вы так имели в виду?

Код:
    myThread1.start();
    myThread2.start();
    qapp.exec();
    myThread1.wait();
    myThread2.wait();
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11213


Просмотр профиля
« Ответ #102 : Август 23, 2010, 16:44 »

Сначала я запускал в main два потока и потом QApplication::exec(). Но ивенты не обрабатывались и окно не прорисовывалось, т.к. QApplication::exec() был блокирован двумя потоками.
Не должен он быть блокирован, на то они и нитки чтобы выполняться параллельно

Код:
    myThread1.start();
    myThread2.start();
    qapp.exec();
    myThread1.wait();
    myThread2.wait();
Да, это правильно и используется в большинстве случаев
Записан
BRE
Гость
« Ответ #103 : Август 23, 2010, 16:51 »

Спасибо, Вы так имели в виду?
Скорее всего ты будешь останавливать свои потоки в какой то другой функции (когда они будут не нужны), вот там вызов wait() будет более уместен.
Записан
labview
Гость
« Ответ #104 : Август 23, 2010, 16:55 »

Ура!!! Всё получилось, работает как я и ожидаю!
Огромнейшее спасибо Вам!
Выкладываю рабочий проект на Ваш просмотр.
Записан
Страниц: 1 ... 5 6 [7] 8   Вверх
  Печать  
 
Перейти в:  


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