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

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

Страниц: 1 ... 4 5 [6] 7 8   Вниз
  Печать  
Автор Тема: Очереди, самодельные сигналы  (Прочитано 71125 раз)
BRE
Гость
« Ответ #75 : Август 18, 2010, 13:26 »

Я не зря написал петлю, она нужна, так как в некоторых случаях поток может проснутся не вовремя...
wait не гарантирует, что проснется только один поток.
В очередь поместили одно задание, 5 потоков ждут на wait. Планировщик может разбудить не один поток, а например 2 (точнее все которые стоят в очереди).
Первый вынимает данные из очереди, следом пробуждается второй поток, для него данных уже нет. Но он проснулся и полез в пустую очередь.
А вот эта петля, как раз уберегает поток от такого поведения, поток просто проверит, что очередь пуста и уснет на wait снова.

На самом деле, мы сейчас обсуждаем настолько примитивные вещи, которых нет пожалуй только в азбуке.
Еще раз порекомендую:
Цитировать
А может стоит разобраться с работой wait condition.
Только основательно.
Записан
labview
Гость
« Ответ #76 : Август 18, 2010, 16:16 »

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

При этом задания будут приходить (добавляться в лист) из разных потоков, а исполнительный поток выбирается индексаторм. Таким образом любой поток может посылать задания любому другому потоку (через глобальный массив Tasking и индексацию массива).
« Последнее редактирование: Август 18, 2010, 16:18 от labview » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #77 : Август 18, 2010, 16:19 »

На самом деле, мы сейчас обсуждаем настолько примитивные вещи, которых нет пожалуй только в азбуке.
Еще раз порекомендую:
Цитировать
А может стоит разобраться с работой wait condition.
Только основательно.
Давайте  основательно Улыбающийся

Я не зря написал петлю, она нужна, так как в некоторых случаях поток может проснутся не вовремя...
wait не гарантирует, что проснется только один поток.
В очередь поместили одно задание, 5 потоков ждут на wait. Планировщик может разбудить не один поток, а например 2 (точнее все которые стоят в очереди).
Первый вынимает данные из очереди, следом пробуждается второй поток, для него данных уже нет. Но он проснулся и полез в пустую очередь.
А вот эта петля, как раз уберегает поток от такого поведения, поток просто проверит, что очередь пуста и уснет на wait снова.
Это так для pthread_cond_signal, который будит "хотя бы 1 нитку" (но может и несколько). Но я вижу что QWaitCondition.wakeOne будит одну (и только одну) нитку (как и сказано в Assistant). Пробуждение остальных пресекается  т.к.  d->wakeups становится равным нулю.

Ну и не мешало бы сразу пояснить что эти проблемы связаны с 2 и более нитками ждущими на 1 QWaitCondition, а то "петля-петля"  Улыбающийся
« Последнее редактирование: Август 19, 2010, 09:59 от Igors » Записан
BRE
Гость
« Ответ #78 : Август 18, 2010, 19:46 »

2 Igors
Я абсолютно серьезно рад тому, что ты основательно разобрался с работой wait condition. Без обид.
Но кроме Qt далеко не все библиотеки (про нативные функции я вообще молчу) занимаются такими чудесами, а это именно чудеса, т.к. большинство специалистов прекрасно знают эти моменты и знают возможности их обхода. Любой программист начавший свою работу с потоками и их синхронизацией используя Qt про эти моменты никогда не узнает, до тех пор пока ему не придется использовать нативные функции или тот-же boost (или в Qt 4.8 решат отказаться от таких чудес?). А после это у этого программиста наступит ступор, потому что у него на Qt аналогичный код работал, а сейчас без Qt - нет. Именно для этого я несколько раз указывал про этот момент с петлей и напишу еще раз:
Специальное не использование петли в этой ситуации это попытка нажить себе большие не приятности с трудно обнаруживаемыми ошибками.
Ты с этим не согласен? Для чего этот спор?
« Последнее редактирование: Август 18, 2010, 19:52 от BRE » Записан
labview
Гость
« Ответ #79 : Август 18, 2010, 22:24 »

Разрешите ещё раз повториться и узнать. Каждому потоку присваевается свой личный объект QWaitCondition, так сделать можно?
И ещё какая принципиальная разница между использованием QWaitCondition и QSemaphore в данном контексте?

Спасибо.
Записан
BRE
Гость
« Ответ #80 : Август 19, 2010, 08:52 »

Каждому потоку присваевается свой личный объект QWaitCondition, так сделать можно?
Объект QWaitCondition связан больше не с потоком, а с данными (очередью) и сигнализирует возможен или нет доступ к ним.
Можно сделать, что бы у каждого потока будет своя защищенная очередь и эти очереди никак не будут пересекаться.
Расскажи подробней, что ты хочешь сделать.
Как я понял, ты хочешь запустить по своему потоку для каждой задачи. А что если в процессе выполнения одна задачу будет выполняться значительно чаще других, то потоки запущенные для других задач будут простаивать? Думаю можно будет обойти данную неприятность, только нужно больше информации по задаче.

И ещё какая принципиальная разница между использованием QWaitCondition и QSemaphore в данном контексте?
У семафоров немного другое предназначение: позволить доступ к ресурсу заданному количеству клиентов, если клиентов больше заданного количества, остальные будут ждать.
При желании можно задать количество клиентов == 1.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #81 : Август 19, 2010, 10:32 »

Ты с этим не согласен? Для чего этот спор?
Да конечно согласен, если бы Вы сразу пояснили - и не пытался бы спорить  Улыбающийся Сам я с мутексами не работаю, нужна скорость, поэтому только OpenMP и atomic

Разрешите ещё раз повториться и узнать. Каждому потоку присваевается свой личный объект QWaitCondition, так сделать можно? И ещё какая принципиальная разница между использованием QWaitCondition и QSemaphore в данном контексте?
Можно и личный объект, но не видно зачем - ведь тогда придется решать какую нитку будить.

Семафор не то чтобы "лучше", но проще в использовании. Заметьте что QWaitCondition нужна "подпорка" (в данном случае проверка "пуста ли очередь"), без этого QWaitCondition не пляшет. А у семафора этой проблемы нет. Оба класса используют примерно одинаковый механизм реализованный на тех же ф-циях ОС, но скорость семафора вдвое выше (хотя это существенно для немногих задач). Можно сказать что QWaitCondition это семафор, обернутый в еще 1 мутекс.

Попробуйте сделать на 1 семафоре (просто 1 глобальный объект QSemaphore) - Вам понравится  Улыбающийся
Записан
BRE
Гость
« Ответ #82 : Август 19, 2010, 10:59 »

Да конечно согласен, если бы Вы сразу пояснили - и не пытался бы спорить  Улыбающийся Сам я с мутексами не работаю, нужна скорость, поэтому только OpenMP и atomic
Честно говоря, я все это писал для labview и людей которые будут это читать позже, которым возможно придется использовать низкоуровневые средства синхронизации. И специально для этого отметил, что петля в данном случае необходима. Кстати, у labview не возникло дополнительных вопросов по этому поводу, но прозвучало твое заявление насчет того, что это все не нужно. Спорить начал ты, вместо того чтобы просто спросить о назначение этой петли. И цель этого мне не понятна.
Хотя судя по всей теме прогресс конечно есть, было узнано:
* как же на самом деле работают условные переменные;
* для чего нужна петля;
* про чудеса внутри QWaitCondition.
Записан
labview
Гость
« Ответ #83 : Август 19, 2010, 14:47 »

Давайте я приведу (выдуманый мной) пример.
Задание: имеются пять внешних приборов, подключеных (допустим) по последовательному интерфейсу к компьютеру: спидометр(датчик скорости), компас (датчик направления), GPS антенна (датчик глобальных координат), руль (актор направления) и педаль газа (актор скорости). Нужно собрать информацию с датчиков, высчитать оптимальное направление и скорость, показать пользователю и передать на акторы (руль и педаль газа). Так же имеется файл, в котором построчно записана траектория движения в виде глобальных координат.
Чтобы не запутаться в программе, нужно логическое разделение программы на модули, к тому же нужно считывать данные асинхронно (т.к. допустим частота передачи данных у всех датчиков отличается) и независимо друг от друга.

Идея состоит в том, чтобы каждый прибор был логически и практически отделён друг от друга. И так каждый модуль состоит из отдельного класса-обьекта, который существует в своём независимом потоке и программно отображает реальный обьект. У каждого такого модуля есть различные задания (tasks). Для межпоточной коммуникации я бы хотел использовать не сигналы и слоты, а лист (буфер) заданий.

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

Решение задания я себе представляю таким.
Модули:
1. главный, отвечающий за интерфейс пользователя GUI, с обработкой событий (нажатия на кнопки и прочее) и представление данных на гуе.
2. спидометр (возможные задание: открыть порт, закрыть порт, считывать скорость по мере поступления пакета в порт, закончить поток)
3. компас (аналогично спидометру)
4. GPS (аналогично спидометру)
5. траектория (открыть файл, закрыть файл, считать следующую позицию траектории, закончить поток)
6. алгоритм (получи скорость, получи направление, получи настоящиие координаты, получи заданные координаты траектории, закончить поток)
7. руль (открыть порт, закрыть порт, поверни на определённый угол, закончить поток)
8. педаль газа (аналогично рулю)

В main мы создаём 7 листов с заданиями (массив листов) и стартуем 7 QThread передавая каждому в конструктор этот глобальный массив листов. Каждый модуль может отправлять задания каждому другому модулю. В функции run() каждого модуля имеется цикл while, где в самом начале проверяется есть ли задание для исполнения. Если задания не имеется, то модуль ничего не делает(спит не потребляя никаких ресурсов).
Записан
BRE
Гость
« Ответ #84 : Август 19, 2010, 15:54 »

Честно говоря этот пример показывает, что команды никакие не нужны.
Все сенсоры работают по следующему принципу:
Сенсор::run()
{
   открыть порт;
   while( !exit )
   {
      читать значение;
      сообщить значение;
   }
   закрыть порт;
}

Здесь как раз система сигнал/слот подходит больше всего.
IMHO, не очень удачный пример. Какие задания ты планируешь давать сенсорам?
Записан
labview
Гость
« Ответ #85 : Август 19, 2010, 15:58 »

Самим сенсорам никаких заданий я давать не хочу, а вот программному сенсорному модулю хочу. Задание считать значение например, или считать 10 значений или считывать значения постоянно, пока не придёт другое задание.

Отркыть порт и закрыть порт, тоже являются заданиями, т.к. порт может поменятся во время исполнения программы (если например юзер подключит сенсор к другому COM-порту и поменяет установки программы). Мне тогда что выходить из потока? В принципе тоже возможно, но не желательно.

Я не собираюсь спорить о целесообразности такого способа программирования, я прошу у вас совета как это реализовать в Qt. Как программист я уже профессионально с 2005 года работаю с подобными проектами (на данный момент сделал около 40 проектов). Вот например один из них (см. скрин).
Прога состоит из двух главыных потоков, где один обрабатывает события гуя, а второй выводит данные на гуй, снизу находятся 11 модулей.
« Последнее редактирование: Август 19, 2010, 16:18 от labview » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #86 : Август 19, 2010, 16:28 »

[offtop]вы же вроде только недавно знакомы с с++ или я вас с кем-то путаю?
кроме того, программироание на qt отличается от программирования на "обычном" с++\жава и .нете
так что лучше прислушиваться к советам)
[/offtop]
ваш пример реализуется так как вы хотите на обычных плюсах. С сигналами\слотами все будет гораздо проще и как раз способствует разделению на части (ни 1 объект не знает ничего о других, а в вашем случае все они должны знать об очереди)
« Последнее редактирование: Август 19, 2010, 16:31 от Авварон » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #87 : Август 19, 2010, 16:28 »

Наверное вместо "закончить поток" Вы хотели сказать "усыпить поток", т.е. уйти на ожидание.
Задача выглядит приятно, т.к. в ней много мест независимых друг от друга. Не видно зачем передавать 7 листов в 7 ниток. Первые 4 сами прекрасно знают что им делать. Пятая (траектория) - зависима и запускать для нее нитку не имеет смысла. Лучше просто загрузить весь файл траектории в память и сделать этот расчет частью алгоритма (6). Также с 7 и 8 - если они могут как-то "ответить" (напр. поворот руля завершен) то делать их нитками, иначе незачем.

Механизм взаимодействия ниток - ну практически подойдет любой  Улыбающийся Не вижу здесь никакой очереди и приоритетов, т.к интересны/существенны только текущие (последние) сигналы с датчиков. Грубо говоря:

- алгоритм (6) делает копию данных посланные датчиками (1-4), выполняет расчет и командует акторами (7-8). Это все

Понимаю что все это выглядит довольно "абстрактно" (недостаточно конкретно) но такова и задача выдуманная Вами  Улыбающийся
Записан
labview
Гость
« Ответ #88 : Август 19, 2010, 17:08 »

Авварон, не путаете, я правда новичёк в сях и кути. Я выше описал "проблемы" использования системы сигналов и слотов. На вопрос обработки сигнала в run() я ответа не получил. Получается если в слоте/слотах я выполняю действия с обьектом, то зачем мне нужен run()? Я хотел чтобы обьект (как и реальный) жил своей жизнью (параллельно к другим), но если от обьекта ничего не требуется, то и спал бы себе. К советам я прислушиваюсь, поэтому и сижу в форуме, а не программирую сам по себе.

Igors, я имел в виду именно закончить поток (например если юзер захочет выйти ит программы, то все потоки получают задание "exit"), а не усыпить его. Усыпает он сам по себе, когда задание выполнено, и на данный момент нет новых заданий. По примеру, да он не совсем конкретный, т.к. выдуманый мной.
Такой вопрос: если файл с траекторией очень большой (например 1 гиг), то зачем мне держать его в памяти? По остальному может быть где то соглашусь, но т.к. пример абстрактный, то не стоит это обсуждать. Просто иногда бывают не просто сенсоры, а умные сенсоры с настройками или командами. Некоторые сенсоры отсылают данные постоянно, некоторые по запросу. В этом абстрактном примере я просто примерно рассказал о применении такого способа программирования.

Спасибо за Ваши ответы.
Записан
labview
Гость
« Ответ #89 : Август 19, 2010, 18:27 »

Если я нажимаю на кнопку на интерфейсе и вызываю слот, который был определён в одном из QThread, то функция в слоте выполняется в том же QThread или в другом, одним на все QThread?
Если объекты находятся в разных потоках (посылающий и принимающий) и используется не DirectConnection, то слот будет отрабатывать в контексте принимающего потока.

Встроил дибаг-сообщения в отправителя сигнала, получателя сигнала и потока. Получатель сигнала (слот) определён в классе QThread, отправитель в главном потоке, DirectConnection не использую. Почемуто номера потоков отправителя и получателя совпадают.

Код:
emit SIGNAL thread id is:  0x15a8
SLOT SerialThread::TX id is:  0x15a8
SerialThread::run() id is:  0x157c
« Последнее редактирование: Август 19, 2010, 18:29 от labview » Записан
Страниц: 1 ... 4 5 [6] 7 8   Вверх
  Печать  
 
Перейти в:  


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