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

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

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Как узнать кто излучил сигнал?  (Прочитано 18802 раз)
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #15 : Февраль 06, 2011, 22:20 »

не чревато, у меня рабочий проект, веб-серфер работает как раз по такому принципу: второстепенные потоки шлют сигналы на главный гуишный поток (с целью создания qwebview), тип сигнала directconnection. Потоков доходило одновременно до 400, проблем никаких никогда не возникало.
у меня тоже на linux'e нормально работало, но при переносе  на винду всё полетело. По сигналу из дочернего потока нужно было сделать ресайз окна... так вот это и падало. Да и прогрес бар не обновлялся.
Дело в том, что при директ коннекшине код ГУИ потока будет исполняться в дочернем потоке, что само по себе опасно. Некоторые системы, например, иксы это могут переваривать, а некоторые - нет. (мог ошибиться в своих выводах)
То что у вас не возникало проблем - ИМХО чистая удача...
ЗЫ: сейчас попробую набросать пример.
Сорри, спутал, у меня directconnection был когда проект писался на Qt Jambi. В сишном варианте сейчас посмотрел - QueuedConnection, работает одинаково в винде и линуксе.
Записан

kubuntu/Win7/x64/NetBeans
Fat-Zer
Гость
« Ответ #16 : Февраль 06, 2011, 22:27 »

А вот и пример(в аттаче)
Оказывается наврал... на линуксе тоже падает, зато хорошо показыват что так делать нельзя.
Видимо зависит от линукса и от версии кьют. У меня не падает, но при директе гадит:
Код:
QObject::setParent: Cannot set parent, new parent is in a different thread
что вполне естественно. Улыбающийся
под дебагом запускал, поэтому на ругань не обратил внимания...  в аттаче попровленный пример...
Вот что странно... если сначала запустить с QueuedConnection, а потом с директ, то всё работает (и плюётся сообщениями даже если не указывать предка в конструкторе), а если сразу с директ то рушится... почему - не понятно(почему работает... идеи?)...

Сорри, спутал, у меня directconnection был когда проект писался на Qt Jambi. В сишном варианте сейчас посмотрел - QueuedConnection, работает одинаково в винде и линуксе.
бывает...  Подмигивающий
Записан
maxxant
Гость
« Ответ #17 : Февраль 06, 2011, 23:40 »

В общем, имхо, ссылка на объект-источник типа QPointer передаваемая с сигналом - это получше будет и поуниверсальнее, хотя и "более тяжелая конструкция". но QPointer::isNull() удобен.

для межпоточных взаимодействий QPointer кривой by disign.  isNull() не атомарен и не гарантирует ничего на следующем же такте процессора. Его можно использовать только в одном потоке. Подробнее об этом написано в доках.

Для межпоточных вещей есть пара из указателей QSharedPointer и QWeakPointer - если конечно хотите обойтись без мютексов и т.п.
Записан
Denjs
Гость
« Ответ #18 : Февраль 07, 2011, 00:00 »

для межпоточных взаимодействий QPointer кривой by disign.  isNull() не атомарен и не гарантирует ничего на следующем же такте процессора. Его можно использовать только в одном потоке. Подробнее об этом написано в доках.

Для межпоточных вещей есть пара из указателей QSharedPointer и QWeakPointer - если конечно хотите обойтись без мютексов и т.п.
о как! секнкс) не дочитал, ассистант громаден как БСЭ)
Записан
juvf
Программист
*****
Offline Offline

Сообщений: 570


Просмотр профиля
« Ответ #19 : Февраль 07, 2011, 06:30 »

Цитировать
Для межпоточных вещей есть пара из указателей QSharedPointer и QWeakPointer - если конечно хотите обойтись без мютексов и т.п.
Что-то всё как-то сложно..... QPointer...... который не работает....... потом пара из указателей QSharedPointer и QWeakPointer.......

я сделал просто, в лоб
Код:
emit(mySignal(QString, this);
Может такое решение тоже таит подводные камни?

ps
Код:
QObject::setParent: Cannot set parent, new parent is in a different thread
У меня тоже есть такое сообщение. Стал разбираться - действительно, парент создан в ГУИ потоке, а во 2-ом потоке создаю объект и пытаюсь указать родителя, созданного в ГУИ потоке. На работу приложения это не влияет. Приложение работает так, как надо. Поэтому пока на это забил.  Но это сообщение напрягает. По хорошему, надобы разобраться....
Записан
maxxant
Гость
« Ответ #20 : Февраль 07, 2011, 12:48 »

Что-то всё как-то сложно..... QPointer...... который не работает....... потом пара из указателей QSharedPointer и QWeakPointer.......

QPointer работает, но для одного потока, т.е. isNull() не гарантирует что объект не будет удалён в другом потоке. В более ранних версиях Qt была аналогичная функция у  QMutex, сейчас она закомменчена в коде, поскольку не имеет смысла, файл qmutex.cpp:
Код:
    \fn bool QMutex::locked()

    Returns true if the mutex is locked by another thread; otherwise
    returns false.

    It is generally a bad idea to use this function, because code
    that uses it has a race condition. Use tryLock() and unlock()
    instead.

    \oldcode
        bool isLocked = mutex.locked();
    \newcode
        bool isLocked = true;
        if (mutex.tryLock()) {
            mutex.unlock();
            isLocked = false;
        }
    \endcode

Вам нужна блокировка самого объекта, QSharedPointer как раз и позволяет это. В примерах достаточно хорошо всё описано, достаточно один раз разобраться. Единственное, до Qt 4.6 не хватало пары функций для удобного их использования (помоему какого-то конструктора и operator=) - а начиная с 4.6 всё хорошо.

я сделал просто, в лоб
Код:
emit(mySignal(QString, this);
Может такое решение тоже таит подводные камни?

Будет работать, конечно, если вы уверены что указатель на объект будет валиден все время пока принимаются сигналы. Другое дело, что решение такое несколько хрупкое - через какое-то время можно забыть тонкости реализации, и тогда бац, будем валиться - хорошо если постоянно, плохо если эпизодически в самый неподходящий момент.

ps
Код:
QObject::setParent: Cannot set parent, new parent is in a different thread
У меня тоже есть такое сообщение. Стал разбираться - действительно, парент создан в ГУИ потоке, а во 2-ом потоке создаю объект и пытаюсь указать родителя, созданного в ГУИ потоке. На работу приложения это не влияет. Приложение работает так, как надо. Поэтому пока на это забил.  Но это сообщение напрягает. По хорошему, надобы разобраться....

объекту создаваемому во 2-м потоке укажите парента = 0. Qt не может удалять дочерний объект живущий в другом потоке и ставит parent=0 за вас - о чем и предупреждение. Удаляйте его сами при завершении потока, но не забывайте - указатель на этот объект, возможно, кому-то нужен - ведь я так понял, его вы передаёте вместе с сигналом в main thread.

если что, вот примерная реализация для shared-weak pointers

Код:

void run() // второй поток
{
   // safe_object удалиться автоматически при выходе из run() если на него больше нет других указателей QSharedPointer в любых потоках.
   QSharedPointer <MyClass> safe_object = QSharedPointer<MyClass>(new MyClass);

   while(...)
   {
      ...
      // создаём слабую ссылку на объект
      QWeakPointer <MyClass> weak_p = safe_object.toWeakRef();
      emit mySignal(weak_p);
   }

}

mainthread::some_slot(QWeakPointer <MyClass> weak_p)
{
   // safe_object удалиться автоматически при выходе из функции если на него больше нет других указателей QSharedPointer в любых потоках.
   QSharedPointer <MyClass> safe_object = weak_p.toStrongRef();
   if( !safe_object.isNull() )
   {
      // здесь гарантированно указатель будет валиден
      safe_object->foo();
   }
}


пояснения к примеру:
-указатель на объект не должен храниться где-то ещё, кроме shared-weak указателей - иначе сам объект можно будет удалить через delete ... и никто об этом не узнает.
-SharedPointer - содержит атомарный счётчик объектов, при достижении счётчиком нуля объект будет удалён автоматически.
-QWeakPointer - слабая ссылка, по сути это указатель на SharedPointer с атомарными операциями. Сам по себе никогда не задерживает удаление объекта и нужен лишь для получения строгого указателя.
-можно обойтись без QWeakPointer если логика несложна и нет риска хитрым алгоритмом задержать объекты в памяти (вызвать тем самым утечку)
-ну и да, независимо от реализации никто не гарантирует корректность межпоточных операций для данных того объекта, к которому вы обращаетесь из разных потоков (то есть гарантируется только валидность указателя).
« Последнее редактирование: Февраль 07, 2011, 13:11 от maxxant » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Февраль 07, 2011, 14:05 »

Код:
      // создаём слабую ссылку на объект
      QWeakPointer <MyClass> weak_p = safe_object.toWeakRef();
      emit mySignal(weak_p);
Сложновато для понимания и для поддержки. Напр. могут возникнуть казусы если mySignal передает аргумент по ссылке. Есть смысл действовать проще, создав четкие правила кто отвечает за создание и кто за удаление, напр так

Код
C++ (Qt)
// посылающий
emit mySignal(new ClientData(arg1, arg2, &mData));  //  отвечает за создание
 
// получатель
void mySlor( ClientData * src )
{
//.. обработка
delete src;       // отвечает за удаление
}
 
При этом деструктор ClientData может и не удалять какие-то члены - их удаление возьмет на себя отправитель
Записан
juvf
Программист
*****
Offline Offline

Сообщений: 570


Просмотр профиля
« Ответ #22 : Февраль 07, 2011, 14:27 »

Тут понятно, а тут нет....

Ну во первых про то что излучателя может уже не быть не подумал. Но сейчас подумал и в принцепе таких мест нет. излучатель всегда будет жыть. Хотя теоретически в будущем может и не быть. Буду делать защиту.

2maxxant
Во вторых, не понял я вашего примера..... Вот как я сделал
Код:
void MyClass::run() // второй поток
{
   while(...)
   {
      ...
      emit mySignal(this);
   }

}

теперь ваш пример. Требуется в слоте узнать излучателя сигнала. На сколько я понял ваш пример, то с сигналом передается указатель на какой-то объект, созданные во втором потоке, а не указатель на излучателя. может имелось ввиду так ран делать?
Код:
void MyClass::run() // второй поток
{
   // safe_object удалиться автоматически при выходе из run() если на него больше нет других указателей QSharedPointer в любых потоках.
   QSharedPointer <MyClass> safe_object = QSharedPointer<MyClass>(this);

   while(...)
   {
      ...
      // создаём слабую ссылку на объект
      QWeakPointer <MyClass> weak_p = safe_object.toWeakRef();
      emit mySignal(weak_p);
   }

}
Записан
maxxant
Гость
« Ответ #23 : Февраль 07, 2011, 16:41 »

Ну во первых про то что излучателя может уже не быть не подумал. Но сейчас подумал и в принцепе таких мест нет. излучатель всегда будет жыть. Хотя теоретически в будущем может и не быть. Буду делать защиту.

Код:
void MyClass::run() // второй поток
{
   // safe_object удалиться автоматически при выходе из run() если на него больше нет других указателей QSharedPointer в любых потоках.
   QSharedPointer <MyClass> safe_object = QSharedPointer<MyClass>(this);

   while(...)
   {
      ...
      // создаём слабую ссылку на объект
      QWeakPointer <MyClass> weak_p = safe_object.toWeakRef();
      emit mySignal(weak_p);
   }

}

ну может и не заморачиваться действительно - а там в будущем, возможно, найдётся решение получше. Заговорили про QPointer и т.д., я показал примерчик, но про this уже и забыл. Если this засунуть в QSharedPointer, то при удалении последнего указателя уничтожиться и сам объект, что весьма вероятно произойдёт в run(), так лучше не делать конечно ))
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Февраль 07, 2011, 17:02 »

Ну и вообще если планируется QueuedConnection, то лучше run не трогать (не перекрывать). Непрактично - по умолчанию run вызывает exec и нитка может принимать сигналы. А перекрыли - придется проверять eventLoop самому
Записан
SimpleSunny
Гость
« Ответ #25 : Февраль 07, 2011, 21:20 »

Никто же не запрещает в перекрытом run самому вызвать exec.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #26 : Февраль 07, 2011, 21:52 »

Никто же не запрещает в перекрытом run самому вызвать exec.
Конечно - но ведь он управление не отдаст. Не смертельно - но неудобно/непрактично
Записан
BRE
Гость
« Ответ #27 : Февраль 07, 2011, 22:04 »

Конечно - но ведь он управление не отдаст. Не смертельно - но неудобно/непрактично
Код
C++ (Qt)
void Thread::run()
{
QEventLoop loop;
for(;;)
{
...
loop.processEvents();
...
}
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Февраль 07, 2011, 22:16 »

Конечно - но ведь он управление не отдаст. Не смертельно - но неудобно/непрактично
Код
C++ (Qt)
void Thread::run()
{
QEventLoop loop;
for(;;)
{
...
loop.processEvents();
...
}
}
 

Не возражаю, ночто оте точки до и после того - не придется ли там вставлять (утомительный) код?  Улыбающийся Ведь что-то могло случиться в processEvents. Необязательно, но проще работать "сигналами"  с обеих сторон
Записан
BRE
Гость
« Ответ #29 : Февраль 07, 2011, 22:21 »

Не возражаю, ночто оте точки до и после того - не придется ли там вставлять (утомительный) код?  Улыбающийся Ведь что-то могло случиться в processEvents. Необязательно, но проще работать "сигналами"  с обеих сторон
Ээээ. Не очень понял о чем речь.
Что за "утомительный код", что может случиться в processEvents, и что мешает работать сигналами с двух сторон?
Записан
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


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