Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
1

Интереса ради

17.12.2014, 12:41. Просмотров 628. Ответов 19
Метки нет (Все метки)


Прошу строго не судить появилась такая задумка в голове и не знаю можно ли ее решить.

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
34
35
36
37
38
39
class A: public QObject
{
  Q_OBJECT
 public:
  explicit A(QObject *parent = 0);
 private:
  int data;
 signals:
  void sg_get(int);
 public slots:
  void sl_get()
  {
    emit sg_get(data);
  }
}
 
class B: public QObject
{
  Q_OBJECT
 public:
  explicit B(QObject *parent = 0)
  {
    connect( this, SIGNAL(sg_get()), &a, SLOT(sl_get()) );
    connect( &a, SIGNAL(sg_get(int)), this, SLOT(sl_get(int)) );
  }
  int get()
  {
    int data;
    emit sl_get();
    //магия
    return data;
  }
 private:
  A a;
 signals:
  void sg_get();
 public slots:
  void sl_get(int);
}
Я конечно понимаю (наверно понимаю) что это криво и не правильно (наверно неправильно) но хотелось бы это сделать так. Откуда это вообще возникло? - Представ те что A и B в разных потоках и общение должно строго проходить через сигналы и слоты. И вот появилось желание обернуть этот класс A в другой класс что бы на выходи получить обычный класс B который можно было бы использовать без всяких заморочек (в плане соединения сигналов и слотов) а просто вызывая методы.

Помогите меня направить на путь истины =)

p.s. Проблема в строке Магия - я предполагаю что там надо сделать ожидание сигнала из вне. слот в классе Б я написал для логичности но хотелось бы просто как то словить просто сигнал от А в функции get().
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.12.2014, 12:41
Ответы с готовыми решениями:

Двоичные константы (вопрос ради интереса)
Интересна причина, почему нет возможности задавать именно двоичные.

Оценка интереса пользователя
Доброго дня. Прошу помочь решить задачу. Как можно одним показателем оценить, насколько...

Определители (в целях интереса)
Допустим: определители Что то мне кажется ну не может быть в решении такое большое число...

Объект интереса: фискальный регистратор
Здравствуйте уважаемые форумчане. Хочу выяснить максимум полезного о существующих типах фискальных...

19
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 12:46 2
Эм. Ты что сделать-то хочешь?
Ты вообще понимаешь зачем сделали сигналы/слоты в QT? Чтобы было легко и просто связать два и более разных классов, не обладающих никакими сведениями о структуре друг друга.

Добавлено через 1 минуту
Код
emit sl_get();
Как она у тебя вообще компилируется? У тебя ведь класс подобного сигнала не содержит.
0
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 12:59  [ТС] 3
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Эм. Ты что сделать-то хочешь?
Ты вообще понимаешь зачем сделали сигналы/слоты в QT? Чтобы было легко и просто связать два и более разных классов, не обладающих никакими сведениями о структуре друг друга.
Вот что я хочу сделать.
Допустим.
У меня есть класс C - GUI
У меня есть класс A - который находится в другом потоке.
Что бы не городить в классе С кучу слотов и сигналов. Я подумал а нельзя ли обернуть в класс B так что бы просто в классе С можно было написать B::get() без всяких сигналов и слотов.

Добавлено через 2 минуты
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Как она у тебя вообще компилируется? У тебя ведь класс подобного сигнала не содержит.
ошибка там sg_get(). Программу еще не собирал это просто в редакторе написано.

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
34
35
36
37
38
39
40
[CPPQT]
class A: public QObject
{
  Q_OBJECT
 public:
  explicit A(QObject *parent = 0);
 private:
  int data;
 signals:
  void sg_get(int);
 public slots:
  void sl_get()
  {
    emit sg_get(data);
  }
}
 
class B: public QObject
{
  Q_OBJECT
 public:
  explicit B(QObject *parent = 0)
  {
    connect( this, SIGNAL(sg_get()), &a, SLOT(sl_get()) );
    connect( &a, SIGNAL(sg_get(int)), this, SLOT(sl_get(int)) );
  }
  int get()
  {
    int data;
    emit sg_get();
    //магия
    return data;
  }
 private:
  A a;
 signals:
  void sg_get();
 public slots:
  void sl_get(int);
}
[/CPPQT]

Добавлено через 10 минут
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Ты вообще понимаешь зачем сделали сигналы/слоты в QT?
А вот почему я использую здесь сигналы и слоты.
MoveToThread работает странно, однако!
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 13:02 4
Цитата Сообщение от Bmg113 Посмотреть сообщение
Вот что я хочу сделать.
Допустим.
У меня есть класс C - GUI
У меня есть класс A - который находится в другом потоке.
Что бы не городить в классе С кучу слотов и сигналов. Я подумал а нельзя ли обернуть в класс B так что бы просто в классе С можно было написать B::get() без всяких сигналов и слотов.
Так ты вначале напиши простой тестовый прототип, чтобы хотя бы как-то между потоками работало, а потом уже извращениями и оптимизациями занимайся.
Как напишешь - приходи с рабочим кодом прототипа и может я тебе что-то подскажу по этой теме.
0
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 13:06  [ТС] 5
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Так ты вначале напиши простой тестовый прототип, чтобы хотя бы как-то между потоками работало, а потом уже извращениями и оптимизациями занимайся.
Как напишешь - приходи с рабочим кодом прототипа и может я тебе что-то подскажу по этой теме.
Я уже Вам дал ссылку на прототип взаимодействия потока с другим потоком. Где я практически понял, что нельзя вызывать на прямую методы.
А то что я сейчас хочу сделать, нельзя пока написать - потому что нет конкретики в строке "Магия".
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 13:06 6
Ты, судя по всему, немного не понимаешь, что такое потоки и как они функционируют.
Потоки создаются для того, чтобы решать задачи параллельно. Если у тебя задача требует последовательного решения, то нужен ли здесь поток вообще?
0
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 13:12  [ТС] 7
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Потоки создаются для того, чтобы решать задачи параллельно. Если у тебя задача требует последовательного решения, то нужен ли здесь поток вообще?
Представ те так.
Решал второй поток задачу.
А в первом потоке по кнопке "Обновление" я мониторю данные.
Так вот по этой кнопке я делаю запрос о состоянии переменной во втором потоке.
(Пример не настоящий.)
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 13:37 8
Насколько я помню из курса линукса, для того чтобы последовательно вызвать и забрать сведения из потоков и процессов используется такая схема(2 варианта):
Код
1 вариант - с блокировкой..
вызывается функция рассчёта данных в другом потоке, в неё передаётся указатель или ссылка на данные, в которые будут занесены(скопированы) запрашиваемые данные
этот поток блокируется, пока другой поток обсчитывает данные

2 вариант - с сигналами слотами
В этом варианте вызывающий класс содержит SIGNAL для вызова слота класса из другого потока и SLOT для того, чтобы принять данные из того потока
Что-то вроде:
class A //вызывающий
{
signals:
 void needData();
slots:
void dataReceived(data);
}

class B //вызываемый
{
signals:
void dataMade(data);
slots:
void makeData() { data; data=/* данные вычитываются*/ ; emit dataMade(data); }
}

connect(&A, SIGNAL(needData), &B, SLOT(makeData));
connect(&B, SIGNAL(madeData), &A, SLOT(dataReceived));

void A::Функция_запрашивающая_данные_из_другого_потока()
{
emit needData();
// дальнейшие вычисления проводятся в слоте dataReceived, когда данные будут получены
}

void A::dataReceived(data)
{
// Другой поток данные вернул, можешь продолжать вычисления
}
Добавлено через 1 минуту
Это я написал для двух действующих параллельно потоков.

Добавлено через 4 минуты
Цитата Сообщение от Bmg113 Посмотреть сообщение
Решал второй поток задачу.
А в первом потоке по кнопке "Обновление" я мониторю данные.
Так вот по этой кнопке я делаю запрос о состоянии переменной во втором потоке.
(Пример не настоящий.)
Понял. Присмотрись ко второму варианту. Там ты запрашиваешь состояние переменной и программа работает дальше. Как только тебе второй поток состояние переменной отослал - ты его сможешь обработать.
Всё таки советую тебе немного поднять уровень знаний о потоках/процессах и их взаимосвязи, если ты будешь плотнее с ними работать. В интернете статей по теме и прочего есть немало.
0
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 13:41  [ТС] 9
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Это я написал для двух действующих параллельно потоков.
Что бы убрать путаницу у Вас название классов по связям наоборот с моими, но отпишусь по вашим обозначениям.
1). Не подходит, так как класс А предполагается находится в GUI.
2). Это все хорошо. Но мне надо что бы и вызов сигнала и обработка по слоту были в одной функции. А не по раздельности.

Добавлено через 54 секунды
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Всё таки советую тебе немного поднять уровень знаний о потоках/процессах и их взаимосвязи, если ты будешь плотнее с ними работать. В интернете статей по теме и прочего есть немало.
Я знаю как работают потоки и слоты и сигналы. Ладно видимо решений моей задачи нет. Спасибо за помощь.
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 13:58 10
Цитата Сообщение от Bmg113 Посмотреть сообщение
Я знаю как работают потоки и слоты и сигналы. Ладно видимо решений моей задачи нет. Спасибо за помощь.
Я не говорю о слотах и сигнала. Я говорю о потоках и процессах. Решение вашей задачи есть, только оно уже не такое простое. Тогда вам надо будет применять первый вариант или его разновидность.

Цитата Сообщение от Bmg113 Посмотреть сообщение
2). Это все хорошо. Но мне надо что бы и вызов сигнала и обработка по слоту были в одной функции. А не по раздельности.
Это нельзя сделать без какой-либо блокировки исполняемого потока. Тут проблема в том, что раз исполняется функция в другом потоке, то исходный поток не имеет никаких сведений о времени её исполнения.
Так что тут вам нужна будет блокировка исходного потока на время исполнения функции в другом потоке. А вот как она должна быть достигнута - через обычный delay() с расчётом на то, что другой поток за это время завершится. Или же применять блокировку исходного потока через любой из блокировщиков, чтобы когда тот поток завершит исполнение функции - он высылал сигнал на разблокировку исходного потока.
Тогда только по сигналу передавайте ссылку на данные. Желательно, чтобы эти данные были более-менее постоянными(например принадлежали классу, который существует очень долгое время), иначе существует опасность того, что данные будут записаны по вашему адресу тогда, когда сама переменная уже перестанет существовать.
1
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 14:10  [ТС] 11
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Это нельзя сделать без какой-либо блокировки исполняемого потока. Тут проблема в том, что раз исполняется функция в другом потоке, то исходный поток не имеет никаких сведений о времени её исполнения.
Так что тут вам нужна будет блокировка исходного потока на время исполнения функции в другом потоке. А вот как она должна быть достигнута - через обычный delay() с расчётом на то, что другой поток за это время завершится. Или же применять блокировку исходного потока через любой из блокировщиков, чтобы когда тот поток завершит исполнение функции - он высылал сигнал на разблокировку исходного потока.
Тогда только по сигналу передавайте ссылку на данные. Желательно, чтобы эти данные были более-менее постоянными(например принадлежали классу, который существует очень долгое время), иначе существует опасность того, что данные будут записаны по вашему адресу тогда, когда сама переменная уже перестанет существовать.
Вот я тоже пришел к блокировке. Но GUI поток блокировать нежелательно. Так что наверно решений нет. Спасибо.
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 14:15 12
Цитата Сообщение от Bmg113 Посмотреть сообщение
Вот я тоже пришел к блокировке. Но GUI поток блокировать нежелательно. Так что наверно решений нет. Спасибо.
Тогда да, решений нет. Либо одно, либо второе, третьего не дано.
0
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 14:24  [ТС] 13
А вот и решение. Делал не я
1
Вложения
Тип файла: rar untitled3__v2.rar (4.1 Кб, 5 просмотров)
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 15:21 14
Цитата Сообщение от Bmg113 Посмотреть сообщение
А вот и решение. Делал не я
Так это блокировка исходного потока и есть. Хотя я про такой просто способ блокировки забыл, каюсь.
Только здесь есть одно НО, которое надо учитывать:
При BlockingQueuedConnection сам по себе слот в новом потоке будет исполнен только в очереди. Тоесть если до во втором потоке уже исполнялись какие-то действия и были в очереди какие-то действия , то исходный поток будет блокирован на время исполнения всех этих действий + время исполнения самого запроса.

Добавлено через 6 минут
Хотя решение там безусловно интересное, надо будет запомнить: там Qt:irectConnection ставится для того, чтобы исполнять слот заблокированного исходного потока в незаблокированном потоке.
0
202 / 148 / 5
Регистрация: 14.03.2013
Сообщений: 784
17.12.2014, 15:37  [ТС] 15
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Хотя решение там безусловно интересное
Согласен =)
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 16:24 16
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
то исходный поток будет блокирован на время исполнения всех этих действий
Кстати, есть идея как удалить данный фактор. Если критично по времени(чтобы интерфейс особо сильно не зависал при большой очереди операций во втором потоке), то можно тупо приостановить выполнение второго потока через установку у него нижайшего приоритета QThread::IdlePriority, а потом выполнить все необходимые операции в первом. Главное потом надо не забыть второму потоку приоритет вернуть. Ну и разумеется следить, чтобы больше никакие другие потоки в это время с данными второго потока не работали на write.
1
187 / 172 / 38
Регистрация: 03.08.2012
Сообщений: 596
17.12.2014, 18:32 17
Цитата Сообщение от Bmg113 Посмотреть сообщение
то бы не городить в классе С кучу слотов и сигналов. Я подумал а нельзя ли обернуть в класс B так что бы просто в классе С можно было написать B::get() без всяких сигналов и слотов.
Отличный способ без блокировки потока, без сигналов и слотов вызывать методы: QMetaObject::invokeMethod
Для invokeMethod не обязательно объявлять функцию как слот, а можно пометить как Q_INVOKABLE
1
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 19:06 18
Цитата Сообщение от Flassie Посмотреть сообщение
Отличный способ без блокировки потока, без сигналов и слотов вызывать методы: QMetaObject::invokeMethod
Для invokeMethod не обязательно объявлять функцию как слот, а можно пометить как Q_INVOKABLE
А почему не сразу QMetaMethod::invoke()?)
=)
Вообще подобное практически ничем не отличается от connect, но зато имеет усложнённый синтаксис вызова. Оно надо?
0
187 / 172 / 38
Регистрация: 03.08.2012
Сообщений: 596
17.12.2014, 19:08 19
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Вообще подобное практически ничем не отличается от connect, но зато имеет усложнённый синтаксис вызова. Оно надо?
Чтобы не городить сигналы-слоты - да, почему бы и нет?
Особенно когда из другого потока нужно не 1 метод вызывать
0
204 / 164 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.12.2014, 19:49 20
Цитата Сообщение от Flassie Посмотреть сообщение
Чтобы не городить сигналы-слоты - да, почему бы и нет?
Особенно когда из другого потока нужно не 1 метод вызывать
Хорошо. Как бы ты переписал эти два файла, из архива выше? Они не большие. Я их тебе даже здесь приведу:
Код
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class A : public QObject {

    Q_OBJECT

public:
    A() { this->perem = 14; }
private:
    int perem;
public slots:
    void slt_sendPerem_emitter();
signals:
    void sig_sync();
    void sig_sendPerem(int);
};

class B : public QObject {

    Q_OBJECT

public:
    B();
    A *a_obj;
    int getA_perem();
private:
    int perem;
public slots:
    void slt_getPerem(int);
signals:
    void sig_sync();
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
Код
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QDebug>

B *b_obj;
QThread *thr;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    b_obj = new B();
    thr = new QThread();

    b_obj->a_obj->moveToThread( thr );
    thr->start();
}

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

B::B() {

    a_obj = new A();
    this->perem = 256;

    connect( this, SIGNAL(sig_sync()), this->a_obj, SIGNAL(sig_sync()), Qt::BlockingQueuedConnection );
    connect( this->a_obj, SIGNAL(sig_sync()), this->a_obj, SLOT(slt_sendPerem_emitter()) );
    connect( this->a_obj, SIGNAL(sig_sendPerem(int)), this, SLOT(slt_getPerem(int)), Qt::DirectConnection );
}

void A::slt_sendPerem_emitter() {

    emit this->sig_sendPerem( this->perem );
}

void B::slt_getPerem( int p ) {

    this->perem = p;
}

int B::getA_perem() {

    emit this->sig_sync();
    return this->perem;
}

void MainWindow::on_pushButton_clicked()
{
    qDebug() << b_obj->getA_perem();
}
Добавлено через 15 минут
Хотя тут тоже не понятно, зачем все эти connect городить, когда можно было просто передать указатель или ссылку на данные.
Разве что чтобы иметь последнюю запрошенную копию данные в потоке.

Добавлено через 14 минут
сократил
Код
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QThread>
#include <QDebug>
#include <QMainWindow>

#include "ui_mainwindow.h"

namespace Ui {
class MainWindow;
}

class A : public QObject {
    Q_OBJECT
public:
    A() { this->m_perem = 14; }

public slots:
    void getPerem(int &parem) { perem = m_perem; }

private:
    int m_perem;
};

class B : public QObject {
    Q_OBJECT
public:
    B() { connect( this, SIGNAL(getPerem(int&)), this->a_obj, SIGNAL(getPerem(int&)), Qt::BlockingQueuedConnection );} 
    
signals:
    void getA_perem(int &perem);

private:
    A *a_obj{new A()};
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0)
      : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    b_obj->a_obj->moveToThread( thr );
    thr->start();
}
    ~MainWindow() {delete ui; delete thr; delete b_obj;}

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    B *b_obj{new B()};
    QThread *thr{new QThread()};
};

void MainWindow::on_pushButton_clicked()
{
    int perem;
    b_obj->getA_perem(&perem);
    qDebug() << perem;
}

#endif // MAINWINDOW_H
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.12.2014, 19:49

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

Карта города и точки интереса
Доброго времени! Есть файл с координатами вершин(около 7к вершин), есть файл соединяющими их...

Поиск области интереса на изображении
Подскажите алгоритм с помощью которого можно найти прямоугольник на картинке с последующей его...

Чисто из профессионального интереса, как будущий IT-шник
Стало интересно вот что, как происходит просмотр web-страниц с ПК, на всех уровнях кроме...

Книги для изучения квантовой физики из интереса
Прочитал книгу про криптографию, в конце книги говорилось о квантовой криптографии, и немного...


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

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

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