Коммуникация между параллельными потоками
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Коммуникация между параллельными потоками
Хочу рассказать как я реализую коммуникацию между параллельными потоками в моих программах. На данный момент считаю этот способ для меня самым оптимальным. Заранее предупреждаю, что здесь будут использоваться фичи появившиеся только в 8-ой версии LabVIEW.
И так я создаю новый пустой проект в какой нибудь папке, чтобы всё относящееся к этому проекту находилось в одном месте.
Создаю прибор, в который помещаю два цикла, это и будут мои параллельные процессы. Называю этот прибор либо Main.vi либо Start.vi, ну это кто как хочет. Главное знать что этот прибор является главным и первым.
Для начала я покажу пример передачи РАЗНЫХ! данных из одного потока в другой с использованием комманд.
Самое первое это как остановить оба параллельных процесса одной кнопкой? Конечно можно использовать для данного случая локальную переменную, но это не всегда возможно, т.к. процессы могут находится и в разных подприборах. А что же с глобальной переменной? Да, её тоже можно использовать, даже если потоки-процессы находятся в разных подприборах, но а если процессы на разных компьютерах? Для этого есть так называемая Shared Variable, да но и её использование не всегда подходит, т.к. для этого нужен так называемый поллинг (engl. polling). То есть в процессе постоянно придётся "опрашивать" переменную, что я не люблю и никогда не использую в своих программах.
И так, мы хотим остановить оба потока одной кнопкой "stop". Для этого берём для нашего примера Queue типа Boolean.
Запустите этот пример в замедленном действии highlight-модус, т.е. жёлтая лампочка в меню сверху и обратите внимание на нижний поток. Он стоит, там ничего не происходит, пока не нажата кнопка стоп!!! Это говорит о том что нижний поток не требует никаких ресурсов CPU. Если бы мы использовали вместо Queue например локальную переменную, то оба процесса время от времени опрашивали бы эту самую переменную. А у нас выходит что нижний процесс ждёт изменения, без пожирания каких либо ресурсов. В программах с несколькими процессами это не критично, но а если у вас программа из 100 и более параллельных процессов, и каждый время от времени опрашивает переменную, хотя этого можно избежать.
Ещё одним из плюсов такой конструкции является то, что вы можете запросто, без каких либо изменений, разбить этот прибор на подприборы. Но об этом позже.
И так я создаю новый пустой проект в какой нибудь папке, чтобы всё относящееся к этому проекту находилось в одном месте.
Создаю прибор, в который помещаю два цикла, это и будут мои параллельные процессы. Называю этот прибор либо Main.vi либо Start.vi, ну это кто как хочет. Главное знать что этот прибор является главным и первым.
Для начала я покажу пример передачи РАЗНЫХ! данных из одного потока в другой с использованием комманд.
Самое первое это как остановить оба параллельных процесса одной кнопкой? Конечно можно использовать для данного случая локальную переменную, но это не всегда возможно, т.к. процессы могут находится и в разных подприборах. А что же с глобальной переменной? Да, её тоже можно использовать, даже если потоки-процессы находятся в разных подприборах, но а если процессы на разных компьютерах? Для этого есть так называемая Shared Variable, да но и её использование не всегда подходит, т.к. для этого нужен так называемый поллинг (engl. polling). То есть в процессе постоянно придётся "опрашивать" переменную, что я не люблю и никогда не использую в своих программах.
И так, мы хотим остановить оба потока одной кнопкой "stop". Для этого берём для нашего примера Queue типа Boolean.
Запустите этот пример в замедленном действии highlight-модус, т.е. жёлтая лампочка в меню сверху и обратите внимание на нижний поток. Он стоит, там ничего не происходит, пока не нажата кнопка стоп!!! Это говорит о том что нижний поток не требует никаких ресурсов CPU. Если бы мы использовали вместо Queue например локальную переменную, то оба процесса время от времени опрашивали бы эту самую переменную. А у нас выходит что нижний процесс ждёт изменения, без пожирания каких либо ресурсов. В программах с несколькими процессами это не критично, но а если у вас программа из 100 и более параллельных процессов, и каждый время от времени опрашивает переменную, хотя этого можно избежать.
Ещё одним из плюсов такой конструкции является то, что вы можете запросто, без каких либо изменений, разбить этот прибор на подприборы. Но об этом позже.
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Разные типы данных
И так мы хотели уметь не только останавливать потоки одновременно, но и передавать какие нибудь данные из одного в другой. Как же это сделать?
А для этого нам нужна Queue "неопределённого" типа, так как заранее неизвестно что мы хотим передавать из одного потока в другой. Ведь мы хотим передавать либо boolean, либо данные (например цифры или строку). Остановимся для начала на цифрах.
А что значит "неопределённый" тип данных. Я знаю как минимум три:
1. строка, т.е. string
2. variant
3. массив, например типа U8
Почему же строка является неопределённым типом? Да просто можно любой тип, а так же что немаловажно любого размера, переделать в строку, а так же наоборот из строки получить нужный (заранее известный) тип данных. Я использую в своих программах именно строку, т.к. данные переделанные в неё отображаются так же как и в памяти компъютера, не занимая при этом больше места, чем они должны занимать. Так же это более распространённый тип, используемый и в других языках программирования. Кроме того строку можно запросто отправить например через последовательный порт или TCP/IP, для удалённой коммуникации.
И так меняем тип очереди (Queue) с boolean на string.
Самое первое что приходит теперь в голову, как же мне отправлять два разных типа данных в очередь строкового типа?
Да, для этого конвертируем данные в строку с помощью виай Flatten To String перед их отправлением в очередь. И так с верхним циклом вроде бы всё понятно, просто конвертируем какие бы то ни были данные в строку и отправляем в очередь.
А что делать в нижнем цикле? Я предлагаю конвертировать данные из строки обратно в данные используя виай Unflatten From String.
Да, но ведь тип должен быть заранее известен! Что же делать, какой тип прицепить сверху этого виай? Ведь у нас их два разных? Выход есть! О типе данных находящихся в "пакете" можно сообщать. Для этого можно просто прицепить его перед самими данными! Вот как это делается. Всё, можно сказать, программа уже работает!
Есть несколько интересных идей как всё сделать удобнее и понятнее, но об этом в следующих уроках.
P.S.
Продолжение вы найдёте в этой теме:
/viewtopic.php?f=23&t=159
А для этого нам нужна Queue "неопределённого" типа, так как заранее неизвестно что мы хотим передавать из одного потока в другой. Ведь мы хотим передавать либо boolean, либо данные (например цифры или строку). Остановимся для начала на цифрах.
А что значит "неопределённый" тип данных. Я знаю как минимум три:
1. строка, т.е. string
2. variant
3. массив, например типа U8
Почему же строка является неопределённым типом? Да просто можно любой тип, а так же что немаловажно любого размера, переделать в строку, а так же наоборот из строки получить нужный (заранее известный) тип данных. Я использую в своих программах именно строку, т.к. данные переделанные в неё отображаются так же как и в памяти компъютера, не занимая при этом больше места, чем они должны занимать. Так же это более распространённый тип, используемый и в других языках программирования. Кроме того строку можно запросто отправить например через последовательный порт или TCP/IP, для удалённой коммуникации.
И так меняем тип очереди (Queue) с boolean на string.
Самое первое что приходит теперь в голову, как же мне отправлять два разных типа данных в очередь строкового типа?
Да, для этого конвертируем данные в строку с помощью виай Flatten To String перед их отправлением в очередь. И так с верхним циклом вроде бы всё понятно, просто конвертируем какие бы то ни были данные в строку и отправляем в очередь.
А что делать в нижнем цикле? Я предлагаю конвертировать данные из строки обратно в данные используя виай Unflatten From String.
Да, но ведь тип должен быть заранее известен! Что же делать, какой тип прицепить сверху этого виай? Ведь у нас их два разных? Выход есть! О типе данных находящихся в "пакете" можно сообщать. Для этого можно просто прицепить его перед самими данными! Вот как это делается. Всё, можно сказать, программа уже работает!
Есть несколько интересных идей как всё сделать удобнее и понятнее, но об этом в следующих уроках.
P.S.
Продолжение вы найдёте в этой теме:
/viewtopic.php?f=23&t=159
Re:
работаю в 7 лв. восьмого пока нет. спасибо, что выложил картинки, т.к. в 7 файл не открывается. по поводу 8-го. вопрос. распространяется он почти свободно. но активировать его нужно только через инет. и , говорят, что необходимо постоянное подключение к инету для стабильной работы программы(так ли это?), что на нашем предприятии невозможно.
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Re: Коммуникация между параллельными потоками
Нет, интернет нужен только один раз для активации. Потом можно работать без интернета.
-
mzu2006
- doctor
- Сообщения: 2456
- Зарегистрирован: 16 авг 2008, 02:12
- Награды: 3
- Версия LabVIEW: 7.1 10 11 12
- Откуда: St-Petersburg (RU), Phila, Boston, Washington DC
- Контактная информация:
Re: Коммуникация между параллельными потоками
А какая именно из фич появилась только в восьмой версии?
Правила форума (Forum rules in Russian)
rm -rf /mnt/windows
rm -rf /mnt/windows
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Re: Коммуникация между параллельными потоками
Rest of Binary Stringmzu2006 писал(а):А какая именно из фич появилась только в восьмой версии?
-
Forward
- professional
- Сообщения: 337
- Зарегистрирован: 03 мар 2008, 12:41
- Награды: 3
- Версия LabVIEW: 2010
- Откуда: Кишинев
- Контактная информация:
Re: Коммуникация между параллельными потоками
Не совсем разобрался. Допустим у меня 3 потока:
1) главный с ивент структурой (отвечает за лицевую панель)
2) работа с портом
3) различная обработка
В случае непрерывного чтения с порта поток 2 постоянно сливает данные через очередь потоку 3, где данные обрабатываются и отправляются в поток 1 по юзер ивет, где визуализируются. Допустим в потоке 3 у меня есть фильтр, параметры которого меняются с лицевой панели (т.е. с потока 1) по событию. Сам же поток 3 висит пока не пришел новый пакет из потока 2. Так вот как лучше в поток 3 заливать параметры обработки (фильтра), частота изменений которых очень мала?
Или же вообще как-то по другому все лучше делать?
1) главный с ивент структурой (отвечает за лицевую панель)
2) работа с портом
3) различная обработка
В случае непрерывного чтения с порта поток 2 постоянно сливает данные через очередь потоку 3, где данные обрабатываются и отправляются в поток 1 по юзер ивет, где визуализируются. Допустим в потоке 3 у меня есть фильтр, параметры которого меняются с лицевой панели (т.е. с потока 1) по событию. Сам же поток 3 висит пока не пришел новый пакет из потока 2. Так вот как лучше в поток 3 заливать параметры обработки (фильтра), частота изменений которых очень мала?
Или же вообще как-то по другому все лучше делать?
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Re: Коммуникация между параллельными потоками
Но ведь твой третий поток может принимать команды с первого и со второго потока, или что то ему мешает? Конечно он может, почему он должен висеть и ждать пока не придёт команда со второго потока?
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Re: Коммуникация между параллельными потоками
Если ты скачал мою библиотеку Tasking, то можешь попробовать вот этот пример:
- Вложения
-
- Tasking_Example(2).vi
- (36.87 КБ) 804 скачивания
-
Forward
- professional
- Сообщения: 337
- Зарегистрирован: 03 мар 2008, 12:41
- Награды: 3
- Версия LabVIEW: 2010
- Откуда: Кишинев
- Контактная информация:
Re: Коммуникация между параллельными потоками
Скорость работы всех потоков разная. Поток 2 "Драйвер работы с портом" работает быстрее всех. Поток 3 "Обработчик" работает медленнее драйвера, но быстрее потока 1 (самый медленный), который обновляет индикаторы.
Какой наиболее элегантный выход? Пропускать данные? Или же тормозить поток работы с портом?
Какой наиболее элегантный выход? Пропускать данные? Или же тормозить поток работы с портом?
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Re: Коммуникация между параллельными потоками
Тот поток что работает с драйвером отсылает данные с прибора обработчику и обработчик обрабатывает их. У них как минимум одна и та должна быть же скорость. Обработчик обязан принимать все данные из первого потока иначе очередь рано или поздно переполнится.
Что касается данных из обработчика третьему потоку, который показывает данные на ЛП. Здесь можно поступить так:
т.к. если например данные идут с частотой в 100 герц, ты не можешь их все показывать на ЛП, это понятно, потому что во-первых ничего видно не будет, числа будут просто быстро мелькать перед глазами, а во-вторых будет пожираться CPU. Здесь тебе надо решать либо ты выкидываешь данные и показываешь только некоторые из них (например каждую секунду одно значение), либо ты высчитываешь среднее математическое например из 100 данных и передаёшь уже отфильтрованные значения самособой автоматом получается что каждую секунду.
Что касается данных из обработчика третьему потоку, который показывает данные на ЛП. Здесь можно поступить так:
т.к. если например данные идут с частотой в 100 герц, ты не можешь их все показывать на ЛП, это понятно, потому что во-первых ничего видно не будет, числа будут просто быстро мелькать перед глазами, а во-вторых будет пожираться CPU. Здесь тебе надо решать либо ты выкидываешь данные и показываешь только некоторые из них (например каждую секунду одно значение), либо ты высчитываешь среднее математическое например из 100 данных и передаёшь уже отфильтрованные значения самособой автоматом получается что каждую секунду.
-
Forward
- professional
- Сообщения: 337
- Зарегистрирован: 03 мар 2008, 12:41
- Награды: 3
- Версия LabVIEW: 2010
- Откуда: Кишинев
- Контактная информация:
Re: Коммуникация между параллельными потоками
С первым потоком понятно. А по поводу того, что обработчик должен работать быстрее - это не всегда так. Как я в этому могу быть уверен? Я с USB могу получать по 30 Мбайт/сек и над всеми этими данными производится множество различных операций. В итоге обработчик все таки может работать медленнее...
-
Eugen Graf
- guru
- Сообщения: 6502
- Зарегистрирован: 13 ноя 2007, 02:20
- Награды: 4
- Версия LabVIEW: 2009
- Откуда: Saarbrücken
- Контактная информация:
Re: Коммуникация между параллельными потоками
Он может только на короткое время работать медленнее, иначе очередь переполнится. Если нет другого выхода, то тебе придётся выкидывать некоторые данные, не передавая их обработчику. Ну или другой вариант - использовать например нотифаер. А ещё лучше обьеденить первый и второй потоки в один. То есть считал -> сразу обработал, а там уже по усмотрению - некоторые данные потоку лицевой панели, некоторые потоку лог, некоторые в друие потоки.
-
mzu2006
- doctor
- Сообщения: 2456
- Зарегистрирован: 16 авг 2008, 02:12
- Награды: 3
- Версия LabVIEW: 7.1 10 11 12
- Откуда: St-Petersburg (RU), Phila, Boston, Washington DC
- Контактная информация:
Re: Коммуникация между параллельными потоками
Forward писал(а):обработчик должен работать быстрее - это не всегда так
или сохранять их, например на диск.eg писал(а):то тебе придётся выкидывать некоторые данные
А чем это лучше? Быстрее? И как ждать одновременно нотифайера и на очереди?eg писал(а):использовать например нотифаер
очередь на входе потока - одна. В которую пишет и 2 и первый потокиForward писал(а):Допустим в потоке 3 у меня есть фильтр, параметры которого меняются с лицевой панели (т.е. с потока 1) по событию. Сам же поток 3 висит пока не пришел новый пакет из потока 2.
Зависит от того, какое максимальное время реакции системы задано в ТЗ. Для быстрого времени реакции скорее всегоeg писал(а):А ещё лучше обьеденить первый и второй потоки в один.
не прокатит.
Ещё можно поиграть с приоритетами выполнения - скажем у потока 2 - макисмальный, у потока 3 чуть меньше и у потока 1
самый маленький. И разнести 1 и (2 и 3) по разным excution systems...
Правила форума (Forum rules in Russian)
rm -rf /mnt/windows
rm -rf /mnt/windows