Russian Qt Forum

Qt => Общие вопросы => Тема начата: mhalionn от Сентябрь 29, 2006, 10:44



Название: Thread и ProgressBar в QT
Отправлено: mhalionn от Сентябрь 29, 2006, 10:44
Для передачи данных по tcp\ip я использую отдельный поток. Чтобы отображать состояние использую отдельный VBox с ProgressBar - ом (Или ProgressDialog). В процедуре run() пишу:
...
while((ReadDataLength =Fl_OpenFile ->readBlock(cThreadBuffer,LENGTH_PACKET)) >0)
{
SumLength +=ReadDataLength;
Sct_ConnectSocket ->writeBlock(cThreadBuffer,ReadDataLength);

...

PBr_SendFileProgress ->setProgress(SumLength);
}
VBx_SendFileProgress ->hide();
...
Так вот эта программа приодически зависает, диалог с ProgressBar - ом не закрывается и вообще работает медленней чем хочется. И конечно если убрать строку "PBr_SendFileProgress ->setProgress(SumLength);" все работает зашибись как.
Вопрос: Почему?
И еще при зависании в консоли выводится сообщение: "Xlib: unexpected async reply (sequence 0x2bbd)". Т.е. я так понимаю: асинхронный доступ - это плохо. А как из вторичного потока взаимодействовать лучше всего с GUI?


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Сентябрь 29, 2006, 11:04
Да из негуевого потока в гуевый данные на прямую лучше не отправлять. Попробуй реализовать это сигналими или с помощью QEvent. А вообще, поиском по форуму воспользуйся...


Название: Thread и ProgressBar в QT
Отправлено: Alex03 от Сентябрь 29, 2006, 11:39
А чем Вам QSocket не нравится?


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Сентябрь 29, 2006, 11:42
А зачем, если есть более простые механизмы обмена информацией в одном приложении.


Название: Thread и ProgressBar в QT
Отправлено: Dendy от Сентябрь 29, 2006, 13:02
Ну ясен пень ничё работать не будет. Наличие потенциальной ошибки - баг  в програме. ТьІ делаешь:

Код:
PBr_SendFileProgress ->setProgress(SumLength);


из другого потока. Всё бьІ хорошо, но если специально не оговорено, то метод не является потокобезопастньІм. ДанньІе, которьІми оперирует етот метод внутри могут запросто оказаться разделяемьІми - использоваться из других методов. Например, из методов рисования етого прогрес бара.

Тебе нужно синхронизировать потоки потокобезопасньІми методами. Например, положить собьІтие из второго потока в основной поток с помощью:

Код:
QApplication::postEvent();


В основном потоке приять ето собьІтие и вьІзвать свой:

Код:
PBr_SendFileProgress ->setProgress(SumLength);


Название: Thread и ProgressBar в QT
Отправлено: mhalionn от Сентябрь 29, 2006, 14:39
События - это Очень хорошо. Т.е. все действия связанные с GUI должны происходить в объектах связанных с главным окном? А можно ли в QThread поднять Q_OBJECT. А то возникает ошибка в moc_SEcondThread.cpp. И тогда можно делать emit из второго потока.


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Сентябрь 29, 2006, 14:57
Цитировать
А можно ли в QThread поднять Q_OBJECT. А то возникает ошибка в moc_SEcondThread.cpp.

Тебе обязательно наследоваться от QThread?


Название: Thread и ProgressBar в QT
Отправлено: mhalionn от Сентябрь 29, 2006, 16:11
Мне обязательно заиметь второй поток. И там еще происходит выбор операции для выполнения (Передача разных данных через QSocket). А вообще то я проявил чудеса внимательности и увител сигнал void bytesWritten(int nbytes) - надеюсь вот это чудесное решение.
А вообще и нтерестно можно или нет поднять slots и signals для QThread? Или это абсолютно бредовая затея т.к. уже давно придумали что-то попривлекательнее? :?:


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Сентябрь 29, 2006, 16:18
Это работает. Без вопросов. Сами делали. Только поток - это таже самая программа. И все, что нужно - пользоваться
QThread * QThread::currentThread ()  [static] (для проверки возможности выполнения кода)


Название: Thread и ProgressBar в QT
Отправлено: burkav84 от Сентябрь 30, 2006, 23:15
В 4-й Qt все намного красивее и легче в использовании чем в 3-й. Для того чтобы обратится к функции, работающей с GUI можно не постить эвент (QApplication::postEvent()), а emit signalName(int progressValue), который законектить на слот с установкой заначеняи твоего прогрессбара - сработает QueuedConnection - и ты получишь что тебе надо. Но в 3-й Кьюти такое бы не работало, так как там есть только DirectConnection. А вообще проще всего былобы в папке с экзамплами посмотреть точно то что тебе надо - там есть работа с сокетами и потоками.


Название: Thread и ProgressBar в QT
Отправлено: Alex03 от Октябрь 02, 2006, 06:55
Цитата: "bigirbis"
А зачем, если есть более простые механизмы обмена информацией в одном приложении.


Я имел ввиду не межпоточное взаимодействие, а изначально однопоточное приложение с использованием QSocket.
Во многих случаях этого достаточно, если только mhalionn не собирается гигабайты качать по сотне tcp/ip-соединений и т.д.

В этом (моём) случае надо раелизовать некую машину состояний. Впрочем при использовании QSocket в отдельном потоке (а это кстати уже по любому QT 4.x.x) надо делать то-же самое.

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

ИМХО потоки полезны как рабочие (т.е. числодробилки), в различных серверных приложениях (с кучей соединений), ну и в тех областях где не доступен асинхронный доступ (к файлу/девайсу/сети ...).

QSocket же (точнее его QSocketNotifier) очень хорошо интегрирован во внутренний цикл обработки сообщений (pool()/select() .. WaitFor..()/MsgWaitFor..()).


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Октябрь 02, 2006, 08:27
Вот QSocket я бы точно в отдельный поток вынес, дабы приложение не подвисало...


Название: Thread и ProgressBar в QT
Отправлено: mhalionn от Октябрь 02, 2006, 10:09
Да дело не в количестве переданных и прочитанных байт. tcp/ip используется как интерфейс управления и как следствие возможно достаточно больше время отклика устройства. Поэтому QThread.
Только вот что-то не понятно:
"Только поток - это таже самая программа. И все, что нужно - пользоваться QThread * QThread::currentThread () [static] (для проверки возможности выполнения кода)" - Это в смысле синхронизации потоков или что? В 3 -й "static Qt::HANDLE currentThread();". А как можно правильно выполнить hide() из второго потока? Опять только события?


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Октябрь 02, 2006, 11:48
QApplication::postEvent( someDialog, new QHideEvent );


Название: Thread и ProgressBar в QT
Отправлено: Alex03 от Октябрь 02, 2006, 12:04
Вы меня нифига не понимаете, или имеете неверное представление о QSocket, который предоставляет асинхронный (неблокирующий) доступ к сокету ОС.

При этом сам QSocket на ожидание пакетов приложение (GUI поток) тормозить не будет.

Т.е.
- Вызвали connectToHost() и убежали по делам (вернулись в главный цикл)
- По результату connectToHost через n-ое время нам прилетает сиглал error() или connected(). (в промежутке ещё и hostFound(), но он не так интересен )
Обрабатыаем сигнал, если connected(), то например, передаём данные с помощью  writeBlock(), с обязательным контролем кода возврата и соответствующим "сдвигом передающего буфера". После вызова writeBlock() опять же вернулись в гл. цикл.
- По факту отправки некоторого числа байтиков (не обязательно всех) словили сигнал bytesWritten(nbytes), если надо, опять попытались чёнить послать и вернулись.
и .т.д.
- По приёму ловите сигнал readyRead(), спрашиваете сколько пришло bytesAvailable(), и читаете в буфер с помощью readBlock().

Между вызовами этих сигналов ваше GUI приложение вполне нормально живёт, без всяких тормозов.

Единственное что при этом надо реализовать так это машину состояний для вашего соединения.

ИМХО при грамотном проектировании многое можно сделать в одном потоке ничуть не менее производительнее нежели чем в нескольких. Много-ядерные/процессорные системы не в счёт. :)

P.S. Всё это на примере Qt3, на 4-ой оно ещё развесистей ( QAbstractSocket, QTcpSocket, QUdpSocket и т.д.)


Название: Thread и ProgressBar в QT
Отправлено: bigirbis от Октябрь 02, 2006, 12:14
А если достаточно большие блоки данных идут или сеть хреновая? Все приложение подвиснет?


Название: Thread и ProgressBar в QT
Отправлено: Alex03 от Октябрь 02, 2006, 12:36
Цитата: "bigirbis"
QApplication::postEvent( someDialog, new QHideEvent );


А GUI-ями из левых потоков рулить вообще ИМХО не правильно.
Где гарантия что someDialog - всё ещё валидный указатель? Понятно что можно и это гарантировать, но ....
Т.е. если есть поток занимающийся некой передачей данных по сети, то и пусть сигналит (теми же postEvent()) о том что данные переданны на Х процентов, или там что ошибочка вышла.
А уж GUI поток пусть решает чё ему нарисовать иль скрыть.

добавлено спустя 18 минут:

 
Цитата: "bigirbis"
А если достаточно большие блоки данных идут или сеть хреновая? Все приложение подвиснет?


Нет не подвиснет.
Т.е. много и за раз Вы не передадите/не примите,  writeBlock() возьмёт сколько надо ( зависит от ОС, а м.б. и от qt-внутренних буферов) и эту цифирь Вам же и вернёт.
Кстати системные вызовы ОС поступают точно также.

Впрочем при большом трафике можно уже на нехватку ресурсов нарваться.

Для примера я принимал по сети и отрисовывал ч/б картинку ~692х520  (361920байт) с частотой 7.5 кадра в сек (2714400 байт/сек).
При этом если тормоза и наблюдались на некоторых машинках то не в коде работы с сетью, а в коде преобразования из QImage в QPixmip и отрисовку bitBlt() (В потомке ScrollView), но это уже отдельная песня.
Всё это было несколько лет назад и под линуксом.


Название: Thread и ProgressBar в QT
Отправлено: mhalionn от Октябрь 02, 2006, 14:57
Да ты прав тысячи чертей. Продаю свои руки и ухожу в монастырь завтра. Спасибо за помощь я понял свою непровату.


Название: Thread и ProgressBar в QT
Отправлено: Dendy от Октябрь 02, 2006, 15:19
Alex03, тьІ абсолютно прав.

СокетьІ в Qt3/Qt4 изначально неблокирующие, то-есть их использование из главного потока вполне оправдано, если нужно использовать конечное количество соединений и не на полную загрузку сети/проца.

Работу с сетью в другой поток/потоки следует вьІносить в случаях:

1. Если вьІ используете N соединений, где N - число произвольное и меняется на лету (типа клиент Jabber'а, броузер, али сервер какой-нить).

2. Если вьІ используете сеть на полную загрузку. То-есть отправляете данньІе сразу же как только возможно и принимаете сразу же как только пришли. Если вам нужно забить канал по максимуму. Возможно при етом вьІ почувствуете удар по перфомансу GUI-приложений, так как работа в преобразованием данньІх займёт львиную долю итерации главного цикла.


Название: Thread и ProgressBar в QT
Отправлено: SLiDER от Октябрь 03, 2006, 15:50
Цитата: "Dendy"
при етом вьІ почувствуете удар по перфомансу

Вау, это наверное больно. В аналы, адназначна.  :D  :D  :D


Название: Thread и ProgressBar в QT
Отправлено: Hordi от Октябрь 03, 2006, 17:28
"асинхронный" - это НЕ синоним "неблокируемый"


Название: Thread и ProgressBar в QT
Отправлено: Alex03 от Октябрь 04, 2006, 06:18
Цитата: "Hordi"
"асинхронный" - это НЕ синоним "неблокируемый"


Синоним, не синоним, это к русскому языку.
Какой по Вашему из этих терминов не применим к QSocket?

ИМХО оба термина вполне употребимы к QSocket.

При желании конечно можно пользоваться и блокирующими функциями типа QSocket::waitFor...(), он это уже отдельная песня.


Название: Re: Thread и ProgressBar в QT
Отправлено: sh от Май 28, 2008, 13:57

похожая ситуация

Xlib: unexpected async reply (sequence 0x60fa9)!


выдается это сообщение в консоль, потом программа виснет, используется qt библиотека версии 3.3
используются потоки, которые посылают сигналы, главное приложение их обрабатывает - обмен информацией между приложением и потоками
в чем может быть причина?


Название: Re: Thread и ProgressBar в QT
Отправлено: SLiDER от Май 28, 2008, 19:43

похожая ситуация

Xlib: unexpected async reply (sequence 0x60fa9)!


выдается это сообщение в консоль, потом программа виснет, используется qt библиотека версии 3.3
используются потоки, которые посылают сигналы, главное приложение их обрабатывает - обмен информацией между приложением и потоками
в чем может быть причина?

В тотм, что в тройке сигналы и слоты не потокобезопасны и так делать нельзя.


Название: Re: Thread и ProgressBar в QT
Отправлено: Sergeich от Май 28, 2008, 19:46
В третьей куте нельзя использовать механизм сигналов / слотов между разными потоками. Пользуй postEvent


Название: Re: Thread и ProgressBar в QT
Отправлено: sh от Май 28, 2008, 21:32
В третьей куте нельзя использовать механизм сигналов / слотов между разными потоками. Пользуй postEvent

спасибо за ответ
тогда нужно будет инициализировать дочерние потоки указателем на родительский в очередь которого скидывать сообщения, думаю в слотах обойдусь QMutex'ом

забил на qmutex, сделал через postEvent с qcustomevent


Название: Re: Thread и ProgressBar в QT
Отправлено: Sergeich от Май 29, 2008, 12:17
В дочерние потоки нужно передавать указатель на объект, к-ый будет обрабатывать сообщения от потока. Никаких мьютексов при этом использовать не надо, postEvent - thread-safe метод. Код должен выглядеть приблизительно так:
Определяем событие
Код:
class ProgressEvent : public QEvent
{
public:
  enum { TypeId = QEvent::User + 1001 };
  ProgressEvent( const QString& operation, int progress )
     : QEvent( ProgressEvent::TypeId ), opname(QDeepCopy<QString> (operation) ), prgs(progress) {}
  QString operation() const { return opname; }
  int progress() const { return prgs; }
private:
  QString opname;
  int prgs;
};
Посылаем событие из дочернего потока
Код:
QString opname = "Initializing";
int prgs = 50;
QApplication::postEvent( receiver, new ProgressEvent( opname, prgs ) );
Обрабатываем полученное событие
Код:
bool Receiver::event( QEvent* e )
{
  if ( e->type() ==  ProgressEvent::TypeId ) {
    ProgressEvent* pe = (ProgressEvent*) e;
    progressDialog->setLabelText( pe->operation() );
    progressDialog->setProgress( pe->progress() );
    return true;
  }
  return false;
}


Название: Re: Thread и ProgressBar в QT
Отправлено: Примерный ученик от Июль 24, 2010, 09:21
Sergeich Респект... ;D
Очень толковый примерчик...
Работает как швейцарские часы ::)


Название: Re: Thread и ProgressBar в QT
Отправлено: SABROG от Июль 24, 2010, 13:59
Sergeich Респект... ;D
Очень толковый примерчик...
Работает как швейцарские часы ::)

Ты удивишься какие вещи можно сделать с помощью обычных межпоточных сигналов и слотов. А некропостинг не есть хорошо :)


Название: Re: Thread и ProgressBar в QT
Отправлено: Примерный ученик от Июль 25, 2010, 20:50
В QT3.3.8 он очень и очень ничего ;D