Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.86/21: Рейтинг темы: голосов - 21, средняя оценка - 4.86
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
1

Параллельные потоки в QT

27.07.2016, 13:03. Просмотров 4188. Ответов 26
Метки нет (Все метки)

Здравствуйте! Я новичок в QT,ранее почти не работал с потоками, хотелось бы навести справки как правильно пользоваться потоками,параллельно, прочитал достаточно много, каша в голове, усвоить пока не получается...

Вот пример: есть класс identificator, .h:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class identificator:public QObject {
    Q_OBJECT
public:
    identificator();
    virtual ~identificator();
private:
    int id;
private slots:
    void printID();
public:
    void setID(int i);
    int getID();
signals:
    void finished();
};
.cpp:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "identificator.h"
#include <stdio.h>
identificator::identificator() {
    id=0;
}
 
identificator::~identificator() {
    // TODO Auto-generated destructor stub
}
void identificator::setID(int i)
{
    id=i;
}
int identificator::getID()
{
    return id;
}
void identificator::printID()
{
    for(;;)
    {
        printf("%d\n",this->getID());
    }
    emit finished();
}
а вот main.cpp:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <QtCore>
#include <QCoreApplication>
#include <QApplication>
#include "myThread.h"
#include "identificator.h"
#include <stdio.h>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    printf("Hello\n");
    identificator *first=new identificator();
    identificator *second=new identificator();
    QThread *thread1=new QThread;
    QThread *thread2=new QThread;
    first->setID(3);
    second->setID(4);
    QObject::connect(thread1, SIGNAL(started()), first, SLOT(printID()));
    QObject::connect(thread2, SIGNAL(started()), second, SLOT(printID()));
    QObject::connect(first, SIGNAL(finished()), thread1, SLOT(quit()));
    QObject::connect(second, SIGNAL(finished()), thread2, SLOT(quit()));
    thread1->start();
    thread2->start();
    return a.exec();
}
Ожидаю, что в консоль будет выводится числа 3 и 4, вразнобой,бесконечно долго, но при запуске в консоль выводится только 3.
Очень прошу, объясните мне пожалуйста, как добиться их параллельной работы?
Заранее спасибо!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.07.2016, 13:03
Ответы с готовыми решениями:

Параллельные потоки
Доброй ночи! необходимо написать пример, показывающий параллельную активность потоков. вот если я...

Параллельные потоки и исключения
Здравствуйте всем! Хочу спросить у вас по поводу хорошей практики: работа параллельных...

Параллельные потоки
Может кто-нибудь подсказать, как написать программу, в которой с какой-то определенной точки...

Параллельные потоки
Доброго времени суток, знатоки! Есть задача, написать программу, со сложными и объемными...

26
92 / 92 / 33
Регистрация: 17.03.2012
Сообщений: 536
27.07.2016, 14:15 2
C++ (Qt)
1
2
first->moveToThread(thread1);
second->moveToThread(thread2);
 Комментарий модератора 
Код С++\Qt обрамляется тегом CPPQT.
1
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
27.07.2016, 14:47  [ТС] 3
Вычитал, что алгоритм должен быть примерно такой:

1)Создание потока.
2)Создание объекта и перенос в поток.
3)Установка сигнально слотовых связей.
4)Запуск потока с заданным приориетом.

Поэтому добавил, как посоветовали: moveToThread()
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    printf("Hello\n");
    identificator *first=new identificator();
    identificator *second=new identificator();
    QThread *thread1=new QThread;
    QThread *thread2=new QThread;
    first->setID(3);
    second->setID(4);
    first->moveToThread(thread1);
    second->moveToThread(thread2);
    QObject::connect(thread1, SIGNAL(started()), first, SLOT(printID()));
    QObject::connect(thread2, SIGNAL(started()), second, SLOT(printID()));
    QObject::connect(first, SIGNAL(finished()), thread1, SLOT(quit()));
    QObject::connect(second, SIGNAL(finished()), thread2, SLOT(quit()));
    thread1->start();
    thread2->start();
    return a.exec();;
}
В консоль по-прежнему выводится идентификатор 1го потока.
Нашел пример - http://www.evileg.ru/baza-znan... -v-qt.html ,
реализовал его, работает. Но там другая архитектура, без сигналов и слотов, просто переопределяется метод run(). Я подумал может дело в printf(), заменил его на qDebug(), мне это не помогло.

Буду благодарен за советы и помощь.
0
92 / 92 / 33
Регистрация: 17.03.2012
Сообщений: 536
27.07.2016, 16:19 4
У меня выводит и 3 и 4.
Попробуйте убрать бесконечный цикл, вы увидите, что выводится и 3 и 4.
Попробуйте также добавить
C++ (Qt)
1
qDebug()<<this->thread();
в метод printID() и увидите разные потоки.

 Комментарий модератора 
Код С++\Qt обрамляется тегом CPPQT.
1
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 07:15  [ТС] 5
Изменил .cpp, изменил функцию getID():
C++ (Qt)
1
2
3
4
5
void identificator::printID()
{
qDebug() << this->thread()<< " " <<this->getID();
emit finished();
}
Да, действительно, выводится в консоль информация о потоке и ID потока, НО! Я ставил бесконечный цикл, с целью проверить что они действительно выполняются одновременно и параллельно, т.е. ожидаю увидеть в выводе:
C++ (Qt)
1
2
3
4
5
6
3
4
4
3
3
3
Вместо этого, у меня просто:
C++ (Qt)
1
2
3
4
т.е. потоки работают последовательно. Я пробовал использовать "неправильный" вариант - наследоваться от QThread и переопределять метод run() - потоки работали параллельно, но мне нужно отладить именно этот, "правильный" с точки зрения ООП вариант.
Помогите пожалуйста, заранее спасибо!
0
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
28.07.2016, 07:48 6
Если мне не изменяет память, у потока должна быть определена функция run (в еоторой все и происходит), которая вызывается после start, хотя лучше посмотреть тут, надеюсь поможет
1
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 08:24  [ТС] 7
Цитата Сообщение от mevn Посмотреть сообщение
Если мне не изменяет память, у потока должна быть определена функция run (в еоторой все и происходит), которая вызывается после start, хотя лучше посмотреть тут, надеюсь поможет
Реализовал из той темы один в один 2ой и 3ий способ - в обоих случаях первый поток который стартует, блокирует поток стартующий после него, на время, пока сам не получит сигнал finished. Получается, что это последовательная работа потоков, а не параллельная. Либо у меня проблемы с моим железом....?!

Добавлено через 4 минуты
Понимаю, что все выполняется так: (прошу поправить, если я не прав)

Объект создается в главном потоке, поэтому его функция тоже будет выполнятся в данном потоке - поэтому, если не использовать moveToThread(), то поток просто напросто будет блокировать остальные. Так и было, так и остается, если добавить эту функцию...
0
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
28.07.2016, 08:44 8
Цитата Сообщение от infernocucumber Посмотреть сообщение
Объект создается в главном потоке, поэтому его функция тоже будет выполнятся в данном потоке - поэтому, если не использовать moveToThread(), то поток просто напросто будет блокировать остальные. Так и было, так и остается, если добавить эту функцию...
Если поток блокирует остальные - это не поток (потоки для этого и нужны: выполнять какие-либо операции, и не блокировать работу остального приложения), он просто не создается. Скорее всего в объявлении класса забыли поставить public QThread.
Надо посмотреть код после изменения.

Добавлено через 3 минуты
3ий способ - должен работать. Странно
0
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 08:51  [ТС] 9
Потоки я создаю таким образом, правильно ведь?
C++ (Qt)
1
2
QThread *thread1=new QThread;
QThread *thread2=new QThread;
Сейчас у меня main.cpp выглядит так:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    printf("Hello\n");
    identificator *first=new identificator();
    identificator *second=new identificator();
    QThread *thread1=new QThread;
    QThread *thread2=new QThread;
    first->setID(3);
    second->setID(4);
    first->moveToThread(thread1);
    second->moveToThread(thread2);
    QObject::connect(thread1, SIGNAL(started()), first, SLOT(printID()));
    QObject::connect(thread2, SIGNAL(started()), second, SLOT(printID()));
    QObject::connect(first, SIGNAL(finished()), thread1, SLOT(quit()));
    QObject::connect(second, SIGNAL(finished()), thread2, SLOT(quit()));
    thread1->start();
    thread2->start();
    return a.exec();
}
В моем примере, я не наследуюсь от QThread, а сразу его использую.

P.S. действительно странно, что у меня не работает 3ий пример из той ссылки....
0
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
28.07.2016, 08:59 10
код identificator покажите

Добавлено через 2 минуты
run() - все еще нигде нет
1
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 09:06  [ТС] 11
.h
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
 * identificator.h
 *
 *  Created on: 27.07.2016
 *      Author: Chernykh-IV
 */
 
#ifndef IDENTIFICATOR_H_
#define IDENTIFICATOR_H_
#include <QtCore>
#include <QCoreApplication>
 
class identificator:public QObject {
Q_OBJECT
public:
    identificator(int i);
    virtual ~identificator();
private:
int id;
private slots:
void printID();
public:
void setID(int i);
int getID();
signals:
void finished();
};
 
#endif /* IDENTIFICATOR_H_ */
.cpp
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
 * identificator.cpp
 *
 *  Created on: 27.07.2016
 *      Author: Chernykh-IV
 */
 
#include "identificator.h"
#include <stdio.h>
#include <QDebug>
identificator::identificator(int i) {
id=i;
}
 
identificator::~identificator() {
    // TODO Auto-generated destructor stub
}
void identificator::setID(int i)
{
id=i;
}
int identificator::getID()
{
return id;
}
void identificator::printID()
{
    for(int i=0;i<10;i++)
    {
qDebug()<<" "<<this->getID()<<" "<<i<<" "<<this->thread();
    }emit finished();
 
}
А метод run() у какого объекта должен вызываться? Если у потока, то я использую QThread, у него нет run().
0
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
28.07.2016, 09:29 12

А если так?
C++ (Qt)
1
2
3
4
//private slots:
//void printID();
 public slots:
        void run();
C++ (Qt)
1
2
3
4
5
6
7
8
9
//void identificator::printID()
void run();
{
    for(int i=0;i<10;i++)
    {
qDebug()<<" "<<this->getID()<<" "<<i<<" "<<this->thread();
    }emit finished();
 
}
и в коннекте конечно поменять.
Хотя я бы просто заменил
C++ (Qt)
1
class identificator:public QObject
на
C++ (Qt)
1
class identificator:public QThread
Убрал объявления потоков thread1, thread2 и все что с ними связано. И заменил printID() на run().

Добавлено через 1 минуту
Цитата Сообщение от infernocucumber Посмотреть сообщение
А метод run() у какого объекта должен вызываться? Если у потока, то я использую QThread, у него нет run().
run() - вызываться не должен, он вызывается из start();
0
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 09:40  [ТС] 13
mevn,

Ааа, понял Вас. То что Вы предлагаете - это один из способов, когда класс наследуется от QThread, в его переопределенном методе run() пишется нужные функции. Этот метод работает параллельно, но мне не подходит с точки зрения ООП.

Буду благодарен за советы.
0
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
28.07.2016, 09:57 14
В методе run() - нужные функции пишутся в любом случае (именно тут и выполняется поток).
0
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 10:30  [ТС] 15
т.е. если даже я не использую наследование от QThread, мне в моем классе всеравно нужен метод run()?
0
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
28.07.2016, 11:08 16
Цитата Сообщение от infernocucumber Посмотреть сообщение
т.е. если даже я не использую наследование от QThread, мне в моем классе всеравно нужен метод run()?
Хмм.. Сказал, так... Но это не верно (сам себя немного запутал)

Добавлено через 19 минут
Вот тут есть исходники, с "правильным" и "неправильным" способами использования потоков, может поможет
0
388 / 351 / 62
Регистрация: 29.05.2015
Сообщений: 2,135
28.07.2016, 11:22 17
Цитата Сообщение от infernocucumber Посмотреть сообщение
т.е. если даже я не использую наследование от QThread, мне в моем классе всеравно нужен метод run()?
В методе run пишешь код, который и выполняется в отдельном потоке. Нагугли рабочий пример с потоками, и посмотри как там всё сделано. А ты пытаешься сам чего-то сочинить, и удивляешься что не работает. Было бы удивительно, если бы заработало...
0
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 14:05  [ТС] 18
Цитата Сообщение от alexu_007 Посмотреть сообщение
В методе run пишешь код, который и выполняется в отдельном потоке. Нагугли рабочий пример с потоками, и посмотри как там всё сделано. А ты пытаешься сам чего-то сочинить, и удивляешься что не работает. Было бы удивительно, если бы заработало...
Мне не нужен вариант с наследованием от QThread. Я знаю что он работает, проверял. Не нужен потому что я не знаю как быть, если мне нужно многопоточное приложение, в каждом потоке которого будет выполнятся своя функция, и мне бы пришлось кучу раз создавать новые классы и для них переопределять метод run(). Есть классические примеры, где используется конструкция: 1)создал объект 2)создал поток 3) засунул объект в поток 4)настроил сигналы и слоты 5)запустил. НО у меня ни один не работает. Хочу выяснить причину этого и по вышеописанному шаблону написал простейший класс, как пример.

Заранее благодарю за советы.
0
68 / 68 / 17
Регистрация: 20.01.2015
Сообщений: 347
28.07.2016, 14:51 19
mevn, это не так. run() переопределяется ТОЛЬКО при наследовании.

infernocucumber, если нужно в потоке выполнить только одну функцию, почему не взять QtConcurrent::run()?
http://doc.qt.io/qt-5.7/qtconcurrentrun.html

Но и способ через moveToThread тоже должен работать. Вероятно вывод 10 чисел оказывается быстрее, чем создание второго потока. Поэтому сначала выводится 3 а потом 4. В выводе задержек-то нету.
0
1 / 1 / 1
Регистрация: 26.05.2016
Сообщений: 53
28.07.2016, 15:03  [ТС] 20
Цитата Сообщение от Amok Посмотреть сообщение
infernocucumber, если нужно в потоке выполнить только одну функцию, почему не взять QtConcurrent::run()?
http://doc.qt.io/qt-5.7/qtconcurrentrun.html
http://doc.qt.io/qt-4.8/thread-basics.html
Взял прямо из примера QtConcurrent::run() с doc.qt.io, добавил еще одну функцию подобную hello в main.cpp запустил и точно такая же ситуация - сперва в консоль вывода отрабатывается первая функция, потом вторая.

Цитата Сообщение от Amok Посмотреть сообщение
Но и способ через moveToThread тоже должен работать. Вероятно вывод 10 чисел оказывается быстрее, чем создание второго потока. Поэтому сначала выводится 3 а потом 4. В выводе задержек-то нету.
Должен! Сколько не вижу примеров в интернете с такой же архитектурой - не работают. Попробовал уже на нескольких машинах. Насчет вывода 10 чисел - ставил бесконечность - там бесконечно отрабатывается функция, которая вызывается первой.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.07.2016, 15:03

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Таймер и параллельные потоки
Добрый день, сразу оговорюсь, что прошёлся поиском по темам с запросом &quot;таймер&quot;, &quot;потоки&quot; и т.д. ...

OPENmp параллельные потоки QT
#include &lt;iostream&gt; #include &quot;omp.h&quot; using namespace std; int main() { #pragma omp...

Параллельные потоки в чем соль?
Есть задание: Значения констант и реализуемые потоками функции: o N=3 o Первый поток -...

Как реализовать параллельные потоки
Как реализовать параллельными потоками? Я знаю можно как-то с Paralell For, как его использовать в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.