Russian Qt Forum

Qt => Общие вопросы => Тема начата: kuzulis от Февраль 05, 2009, 16:02



Название: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 05, 2009, 16:02
доброго дня!

= случай №1 = (передаем с помощью сигналов и слотов между объектов ДАННЫЕ!)

main.cpp
Код:
#include <QtCore>
#include <QCoreApplication>

#include "ab.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    A *cA = new A();
    B *cB = new B();
    QObject::connect(cA, SIGNAL(sgFromA(int)), cB, SLOT(slotB(int))); //тут по значению передача данных происходит!!!
    cA->slotA();//запускаем таймер
    return app.exec();
}
ab.h
Код:
#ifndef AB_H
#define AB_H
#include <QDebug>
#include <QTimer>

class A : public QObject
{
    Q_OBJECT
signals:
    void sgFromA(int data);
public:
    A() { cnt = 0; }
public slots:
    void slotA() {//выполняем этот слот сами один раз в main
        qWarning() << "A::slotA() -> GO GO GO";
        QTimer *timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(slotA1()));
        timer->start(1000);
    }
    void slotA1() {//этот слот класса А будет емиттить сигнал с данными для слота В
            ++cnt;
            qWarning() << "A::slotA1() -> sended CNT = " << cnt;
            emit sgFromA(cnt);//здесь передаем ЗНАЧЕНИЕ переменной!
    }
private:
    int cnt;//типа счетчик
};

class B: public QObject
{
    Q_OBJECT
public slots:
    void slotB(int data) {//этот слот класса В будет принимать сигнал от класса А с данными
        qWarning() << "B::slotB() -> received CNT = " << data;
    }
};
#endif // AB_H

= случай №2 = (передаем с помощью сигналов и слотов между объектов УКАЗАТЕЛИ НА ДАННЫЕ!)

main.cpp
Код:
#include <QtCore>
#include <QCoreApplication>

#include "ab.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    A *cA = new A();
    B *cB = new B();
    QObject::connect(cA, SIGNAL(sgFromA(int *)), cB, SLOT(slotB(int *)));
    cA->slotA();//запускаем таймер
    return app.exec();
}
ab.h
Код:
#ifndef AB_H
#define AB_H
#include <QDebug>
#include <QTimer>

class A : public QObject
{
    Q_OBJECT
signals:
    void sgFromA(int *data);
public:
    A() { cnt = 0; }
public slots:
    void slotA() {//выполняем этот слот сами один раз в main
        qWarning() << "A::slotA() -> GO GO GO";
        QTimer *timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(slotA1()));
        timer->start(1000);
    }
    void slotA1() {//этот слот класса А будет емиттить сигнал с данными для слота В
            ++cnt;
            qWarning() << "A::slotA1() -> sended CNT = " << cnt;
            emit sgFromA(&cnt); //здесь передаем АДРЕС переменной!
    }
private:
    int cnt;//типа счетчик
};

class B: public QObject
{
    Q_OBJECT
public slots:
    void slotB(int *data) {//этот слот класса В будет принимать сигнал от класса А с данными
        qWarning() << "B::slotB() -> received CNT = " << *data;//
    }
};
#endif // AB_H

варианты №1 и №2 работают в конечном счете одинаково, НО:
1. Хотелось бы узнать, а в каком случае после компиляции проекта будут БЫСТРЕЕ обратываться данные и меньше будет использование памяти?
    ( т.е в случае №1 - создается дополнительная переменная int data в которую сначала копируется результат счетчика, потом из нее забирается он,
      а в случае №2 все идет по адресу ... т.е мое ИМХО - что так будет быстрее и меньше памяти будет использоваться)
2. Или это не имеет значения, т.к компилятор все-равно оптимизирует код?


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: lit-uriy от Февраль 05, 2009, 16:06
для инта пожалуй все равно, а если посмотреть на то как делают троли, то видно, что для собственных типов данных используют ссылки.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 05, 2009, 16:19
Цитировать
для инта пожалуй все равно, а если посмотреть на то как делают троли, то видно, что для собственных типов данных используют ссылки.
пример в студию! :)

------
т.е
1. если я например в качестве данных передаю например QList - то
в классе A писать:
Код:
signals:
    void sgFromA(QList<*MyDataTypes> *data);
в классе B писать:
Код:
public slots:
    void slotB(QList<*MyDataTypes> *data);
в main писать:
Код:
QObject::connect(cA, SIGNAL(sgFromA(QList<*MyDataTypes> *)), cB, SLOT(slotB(QList<*MyDataTypes> *)); 

?????

2. а если я передаю какой-то свой тип данных типа структуры или класса то:
в классе A писать:
Код:
signals:
    void sgFromA(MyDataTypes *data);
в классе B писать:
Код:
public slots:
    void slotB(MyDataTypes *data);
в main писать:
Код:
QObject::connect(cA, SIGNAL(sgFromA(MyDataTypes *)), cB, SLOT(slotB(MyDataTypes *)); 

???

мне интересно поподробнее это узнать, т.к везде в примерах передают или int или QString.. (из тех примеров что мне попадались)

и еще... а когда целесообразно при передаче параметров писать ключевое слово :
Код:
const

???


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: lit-uriy от Февраль 05, 2009, 16:25
я говорил не об указателях, а о ссылках:
connect(table->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
         this, SLOT(currentChanged()) );


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 05, 2009, 16:30
Цитировать
я говорил не об указателях, а о ссылках:
connect(table->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
         this, SLOT(currentChanged()) );

я ща попробовал с int такое провернуть... работает! :)

но все-таки интересно что быстрее...
1. передавать: data
или
2. передавать: *data
или
3. передавать: const &data
???


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: lit-uriy от Февраль 05, 2009, 16:32
2 и 3 быстрее


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 05, 2009, 16:42
:) ну это вроде понятно..
а вот между 2 и 3 ?


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: ритт от Февраль 05, 2009, 18:31
эмм...не забываем, что для {,Blocking}QueuedConnection все данные копируются через QMetaType::create(), а потом кастятся из void* в требуемый тип...


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 06, 2009, 08:27
Цитировать
эмм...не забываем, что для {,Blocking}QueuedConnection все данные копируются через QMetaType::create(), а потом кастятся из void* в требуемый тип...

т.е? и что это значит? :)

(т.е. на что это сказывается и т.п)

ЗЫ: только по рабоче-крестьянски пжлста...


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: Dendy от Февраль 06, 2009, 12:15
Значит что данные где-то временно сохранятся и будут доставлены в нужный слот позже. То-есть произойдёт многократное копирование. К счастью большинство классов что передаются через сигнал-слот - Implicitly Shared, то-есть операции копирования таких данных атомарны.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: Steven_Orko от Февраль 06, 2009, 12:42
2 и 3 быстрее
Да ну?? Правда? А если так:
Код:
char data[2];

Указатель на data для 32bit занимает 4 байта, а для 64 сами знаете....
Тоже самое и со ссылкой, которая есть ничто иное как разыименованный указатель.
И что в итоге быстрее?

Я к тому, что надо оговаривать конкретный тип данных data. ИМХО, для POD-типов не имеет значение,  как их передавать: по ссылке, значению или указателю, если, конечно, это не огромный цикл копирования...


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 06, 2009, 12:50
так в каких случаях будет временно копирование происходить а в каких нет и если будет - то сколько раз оно будет происходить за передачу?

1. Я передаю через сигнал-слот переменные типов: int,byte,bool - да/нет и сколько раз
2. Я передаю через сигнал-слот ссылку переменной типов: const int &,const byte &,const bool & (и т.п.) - да/нет и сколько раз
3. Я передаю через сигнал-слот ссылку строки типа: const QString & - да/нет и сколько раз
4. Я передаю через сигнал-слот переменную типа QObject (в общем случае): QObject  - да/нет и сколько раз
5. Я передаю через сигнал-слот ссылку типа QObject (в общем случае): const QObject &  - да/нет и сколько раз
6. Я передаю через сигнал-слот свою переменную типа TUserDadaType (в общем случае являющуюся просто классом или структурой, не наследованной ни от чего):
                                                         TUserDadaType - да/нет и сколько раз
6. Я передаю через сигнал-слот свою ссылку переменной типа TUserDadaType (в общем случае являющуюся просто классом или структурой, не наследованной ни от чего):
                                                         const TUserDadaType & - да/нет и сколько раз

ЗЫ: я спрашиваю, потому что у меня приложение собирается быть "большим", т.е многопоточным и должен большой объем данных обрабатываться + ко всему, нужно все это делать как можно быстрее!! т.е скорость должна быть на максимуме! и передачу данных между объектами приложения я пока планирую делать с помощью сигналов-слотов! т.е каждая операция копирования , пересылки и т.п у меня на счету! :)


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 06, 2009, 12:54
Цитировать
И что в итоге быстрее?
я тоже хочу это знать! :)
Цитировать
Тоже самое и со ссылкой, которая есть ничто иное как разыименованный указатель.
так сколько затрачивается шагов в среднем? как это определить?
если:
1. я передаю переменную с помошью сигнал - слот
2. я передаю ссылку с помошью сигнал - слот
3. я передаю указатель с помощью сигнал-слот


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: Dendy от Февраль 06, 2009, 13:16
Дак, а с чего вы решили что количество копирований должно меняться в зависимости от того что передаётся? В случае когда вызов слота синхронный - данные копируются только по стеку. Какая разница сколько времени на это тратится, если новая память в куче не выделяется? Большинство данных копируются одной операцией, а Implicitly Shared классы вообще копируются атомарно. Если вам критично сколько происходит накладных расходов на вызов сигнала - подсоедините его к пустому слоту и замерьте несколько вызовов в цикле:

Код
C++ (Qt)
connect( SIGNAL(mySignal(int)), this, SLOT(mySlot(int)) );
QTime time = QTime::currentTime();
for ( int i = 0; i < 1000000; ++i )
 emit mySignal( 0 );
qDebug() << "Time for one emit: " << (float)time.elapsed()/1000000;
...
void MyClass::mySlot( int )
{
 // empty
}

Добавьте количество аргументов в сигнал/слот и протестируйте. О результатах доложите.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 06, 2009, 14:00
нет, это не то... в этом примере оценивается только время емиттинья сигнала...

а мне (нам) необходимо оценить время, прошедшее от еммитинья сигнала (передачи переменной) до приема сигнала (до того как эту переменную в слоте прочитали)...
т.е время цикла: обработка-передача-прием-обработка

вопрос: есть ли в QT какая нить ф-я для подсчета кол-ва тиков процессора и т.п., т.к оценить время не представляется возможным  т.к. оно оч мало


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: BRE от Февраль 06, 2009, 14:09
нет, это не то... в этом примере оценивается только время емиттинья сигнала...
Как ты себе представляешь [эмиттинье] сигнала?

а мне (нам) необходимо оценить время, прошедшее от еммитинья сигнала (передачи переменной) до приема сигнала (до того как эту переменную в слоте прочитали)...
т.е время цикла: обработка-передача-прием-обработка
В примере измеряется именно это...

т.к оценить время не представляется возможным  т.к. оно оч мало
Для этого и используется в цикле много итераций.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: Rcus от Февраль 06, 2009, 14:31
вопрос: есть ли в QT какая нить ф-я для подсчета кол-ва тиков процессора и т.п., т.к оценить время не представляется возможным  т.к. оно оч мало
http://doc.trolltech.com/4.5/qtestlib-manual.html#creating-a-benchmark


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 06, 2009, 15:03
в общем сделал так: (на примере передачи-приема int )
al.h
Код:
#ifndef AL_H
#define AL_H
#include <QTime>
#include <QDebug>

#define LIMIT 4000000

class TMyClass : public QObject
{
    Q_OBJECT
signals:
    void mySignal(int data);
public:
    TMyClass() {
        cnt = 0;
        srcData = 0;
        dstData = 0;
        connect( this, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)) );
    }
    void myStart() {
        srcData = 333;//в переменную пишем число 333
        time = QTime::currentTime();//получаем текущее время до старта
        for ( int i = 0; i < LIMIT; ++i ) {// LIMIT раз емиттим сигнал с данными
            ++cnt;//счетчик кол-ва итераций
            emit mySignal( srcData );
        }
    }
private slots:
    void mySlot(int data) {
        dstData = data;//копируем в переменную dstData содержимое переменной data
        if (cnt == LIMIT)
            qDebug() << "Time for one cicle ~ " << (float)time.elapsed()/LIMIT;//получаем среднее время цикла обработки
            //qDebug() << "data = " << dstData;
    }
private:
    QTime time;
    int cnt;
    int srcData;
    int dstData;
};
#endif // AL_H
main.cpp
Код:
#include <QtCore>
#include <QCoreApplication>

#include "al.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    TMyClass *MyClass = new TMyClass();
    MyClass->myStart();
    return a.exec();
}

итак в результате 5-ти запусков программы имеем:
1. если передавать int - то время около 0.000961
2. если передавать const int & - то время около 0.000970
3. если передавать int * - то время около 0.000965

т.е с простыми типами данных впринципе наверное одинаково...

ЗЫ: попожжа попробую передавать структуру, массив


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 06, 2009, 15:04
Цитировать
В примере измеряется именно это...
хм... по ходу вы правы :) (я долго думал)


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 11, 2009, 09:30
В общем попробовал передавать в качестве параметра data массив QByteArray на 1000000 элементов
1. Если передавать как QByteArray то среднее время = 0,0011648
2. Если передвать как const QByteArray & то среднее время = 0,00104065

т.е прирост скорости около 10-12 %


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: ритт от Февраль 11, 2009, 10:14
зачем тестировать данные шаренных типов? и так понятно, что разница будет не столь существенна.
вот, к примеру, тест http://labs.trolltech.com/blogs/2009/01/23/iterating-efficiently/ - сравнение выборки (передачи) приведено в таблице.

подитожу то, что многократно уже было сказано (здесь и не только):
при передаче данных через события
* для простых типов (int, bool) используй простые типы (int, bool)
* для шаренных типов (QString, QVariant) используй ссылки (желательно константные) (const QString&, const QVariant&)
* для произвольных типов (нешаренных и непростых) (struct MyStruct, class MyClass) используй ссылки и указатели (const MyStruct&, MyClass*), только если не разрушаешь сущности после отправки (иначе сегфолт). плюс не забывай регистрировать произвольные типы в метаобъектной системе.

упд по последнему пункту: если необходимо разрушить сущности после отправки (выход из функции и т.п.), либо используй передачу с ожиданием (Qt::BlockingQueuedConnection), либо передавай указатели и уничтожай в слоте после отработки.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: kuzulis от Февраль 11, 2009, 10:46
2 Константин ,
спасибо большое! :) Вот этой конкретики и ождал услышать!

только вот насчет разрушения...

например я делаю так:
1.
Код:
void MyClass::MyFunc()
{
   TMyData MyData;
   ...
   ...
   emit (&MyData);
}
тут после выполнения ф-ции MyFunc() , объект MyData автоматически разрушится? т.е так нельзя?
2.
Код:
void MyClass::MyFunc()
{
   TMyData *MyData = new TMyData;
   ...
   ...
   emit (MyData);
}
а вот так можно?



Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: manarch от Февраль 11, 2009, 10:58
Подскажите кто знает. Необходимо передавать небольшой массив данных, причем объем этих данных может менятся, поэтому они выделяются динамически. Возможна передача между несколькими потоками и в виде "точка-многоточка". В ассенте написанно что если передача происходит между разными потоками или тип сигнала Qt::QueuedConnection, то сигнал ставится в очередь. В этом месте и есть загвоздка, т.к. если выделять данные динамически и при этом выделять их локально, то возникает проблема освобождения память выделенной по эти данные. Подскажите как узнать все ли потоки получили эти данные и их можно удалить? При этом информаци о количестве потоков неизвестна, и поэтому счетчик количества потоков обработавших данные внутри структуры этих данных исключается.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: ритт от Февраль 11, 2009, 11:24
использовать данные шаренного типа. например, QByteArray или QVariant


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: BRE от Февраль 11, 2009, 11:48
например я делаю так:
1.
Код:
void MyClass::MyFunc()
{
   TMyData MyData;
   ...
   ...
   emit (&MyData);
}
тут после выполнения ф-ции MyFunc() , объект MyData автоматически разрушится? т.е так нельзя?
Хочу немного добавить.
Нужно понимать, что делаешь. Например, в некоторых случаях можно использовать следующий код.
Код
C++ (Qt)
void MyClass::MyFunc()
{
  TMyData data;
  emit request( data );
 
  // Обработали данные
  if( data.var1 == 1234 )
      ....
 
  // data - разрушился, ибо нефик.
}
 
void MyLister::request( MyData &data )
{
   // Заполнили поля структуры
   data.var1 = 1234;
   data.var2 = 5678;
}
 



Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: ритт от Февраль 11, 2009, 11:56
BRE, нельзя, если речь идёт об асинхронном вызове. если при этом TMyData - шаренный тип, то можно...но смысла в контексте примера выше 0.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: BRE от Февраль 11, 2009, 11:59
BRE, нельзя, если речь идёт об асинхронном вызове.
Поэтому, я сразу написал "в некоторых случаях".  :)
Если человек понимает что делает, то можно.


Название: Re: Сигналы, слоты + передача с помощью них данных?
Отправлено: Dendy от Февраль 12, 2009, 10:58
2 manarch. Лучше всего засунуть ваши данные в QSharedDataPointer, превратив их в Implicitly Shared класс. Таким образом копирование для чтения будет атомарной операцией, обьект будет уничтожен когда уничтожится последняя ссылка на него, передавать такой класс можно безопастно между потоками, самому удалять данные не нужно. Подробней в документации по QSharedDataPointer.