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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Thread и ProgressBar в QT  (Прочитано 23076 раз)
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?
Записан
bigirbis
Гость
« Ответ #1 : Сентябрь 29, 2006, 11:04 »

Да из негуевого потока в гуевый данные на прямую лучше не отправлять. Попробуй реализовать это сигналими или с помощью QEvent. А вообще, поиском по форуму воспользуйся...
Записан
Alex03
Гость
« Ответ #2 : Сентябрь 29, 2006, 11:39 »

А чем Вам QSocket не нравится?
Записан
bigirbis
Гость
« Ответ #3 : Сентябрь 29, 2006, 11:42 »

А зачем, если есть более простые механизмы обмена информацией в одном приложении.
Записан
Dendy
Гость
« Ответ #4 : Сентябрь 29, 2006, 13:02 »

Ну ясен пень ничё работать не будет. Наличие потенциальной ошибки - баг  в програме. ТьІ делаешь:

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


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

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

Код:
QApplication::postEvent();


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

Код:
PBr_SendFileProgress ->setProgress(SumLength);
Записан
mhalionn
Гость
« Ответ #5 : Сентябрь 29, 2006, 14:39 »

События - это Очень хорошо. Т.е. все действия связанные с GUI должны происходить в объектах связанных с главным окном? А можно ли в QThread поднять Q_OBJECT. А то возникает ошибка в moc_SEcondThread.cpp. И тогда можно делать emit из второго потока.
Записан
bigirbis
Гость
« Ответ #6 : Сентябрь 29, 2006, 14:57 »

Цитировать
А можно ли в QThread поднять Q_OBJECT. А то возникает ошибка в moc_SEcondThread.cpp.

Тебе обязательно наследоваться от QThread?
Записан
mhalionn
Гость
« Ответ #7 : Сентябрь 29, 2006, 16:11 »

Мне обязательно заиметь второй поток. И там еще происходит выбор операции для выполнения (Передача разных данных через QSocket). А вообще то я проявил чудеса внимательности и увител сигнал void bytesWritten(int nbytes) - надеюсь вот это чудесное решение.
А вообще и нтерестно можно или нет поднять slots и signals для QThread? Или это абсолютно бредовая затея т.к. уже давно придумали что-то попривлекательнее? :?:
Записан
bigirbis
Гость
« Ответ #8 : Сентябрь 29, 2006, 16:18 »

Это работает. Без вопросов. Сами делали. Только поток - это таже самая программа. И все, что нужно - пользоваться
QThread * QThread::currentThread ()  [static] (для проверки возможности выполнения кода)
Записан
burkav84
Гость
« Ответ #9 : Сентябрь 30, 2006, 23:15 »

В 4-й Qt все намного красивее и легче в использовании чем в 3-й. Для того чтобы обратится к функции, работающей с GUI можно не постить эвент (QApplication::postEvent()), а emit signalName(int progressValue), который законектить на слот с установкой заначеняи твоего прогрессбара - сработает QueuedConnection - и ты получишь что тебе надо. Но в 3-й Кьюти такое бы не работало, так как там есть только DirectConnection. А вообще проще всего былобы в папке с экзамплами посмотреть точно то что тебе надо - там есть работа с сокетами и потоками.
Записан
Alex03
Гость
« Ответ #10 : Октябрь 02, 2006, 06:55 »

Цитата: "bigirbis"
А зачем, если есть более простые механизмы обмена информацией в одном приложении.


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

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

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

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

QSocket же (точнее его QSocketNotifier) очень хорошо интегрирован во внутренний цикл обработки сообщений (pool()/select() .. WaitFor..()/MsgWaitFor..()).
Записан
bigirbis
Гость
« Ответ #11 : Октябрь 02, 2006, 08:27 »

Вот QSocket я бы точно в отдельный поток вынес, дабы приложение не подвисало...
Записан
mhalionn
Гость
« Ответ #12 : Октябрь 02, 2006, 10:09 »

Да дело не в количестве переданных и прочитанных байт. tcp/ip используется как интерфейс управления и как следствие возможно достаточно больше время отклика устройства. Поэтому QThread.
Только вот что-то не понятно:
"Только поток - это таже самая программа. И все, что нужно - пользоваться QThread * QThread::currentThread () [static] (для проверки возможности выполнения кода)" - Это в смысле синхронизации потоков или что? В 3 -й "static Qt::HANDLE currentThread();". А как можно правильно выполнить hide() из второго потока? Опять только события?
Записан
bigirbis
Гость
« Ответ #13 : Октябрь 02, 2006, 11:48 »

QApplication::postEvent( someDialog, new QHideEvent );
Записан
Alex03
Гость
« Ответ #14 : Октябрь 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 и т.д.)
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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