Tasking2 Library

Общие принципы, проектирование, модуляризация, темплейты и шаблоны
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Tasking2 Library

Сообщение Eugen Graf »

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

Структура библиотеки думаю понятна, как обычно Open, Read, Write, Close. Так же в библиотеке имеется темплейт с коментариями, который сильно облегчает работу с этой библиотекой.

И так к делу :clap:

1. Создаём проект и главный виртуальный прибор Main.vi. В палитре ищем вышеназваный темплейт и располагаем его на блок-диаграмме.
1.png
2. Создаём контрол Enum-Typedef в котором мы перечислим все параллельные потоки, средством общения которых являются очереди (Queue).
2.png
3. Предположим у нас в проекте будет три параллельных потока-цикла While, один из которых будет находится в Main.vi и два в подприборах SubVI 1 и SubVI 2.
3.png
4. Подменяем номер таска на только что созданый нами контрол. Убираем коментарий.
4.png
5. Создаём ещё один контрол Enum-Typedef, в котором мы перечислим все глобальные команды (в данном примере это одна команда exit) и подменим им нумерик для глобальных команд. Убираем коментарий.

О глобальных командах. В этой библиотеке я разделил команды на локальные (у каждого потока свой список локальных команд) и глобальные, на которые должны реагировать сразу все потоки. В дальнейшем вы поймёте, что это удобно.
5.png
6. Создаём ещё один контрол Enum-Typedef для локальных команд главного цикла находящегося в Main.vi. Заносим в список две команды Data from SubVI 1 и Data from SubVI 2. Подменяем им нумерик константу как показано на скрине. Убираем коментарий.
6.png
7. По принципу описаному в пунктах 5 и 6 подменяем номер таска и Enum с глобальными командами для SubVI 1 и SubVI 2, так же создаём списки локальных команд для этих подприборов.
7.png
8. При этом важно указать правильное название таска (смотрим скрин)
8.png
9. В Main.vi добавляем ещё один дополнительный цикл для обработки ивентов (нажатия на кнопки и прочее).
9.png
10. Добавляем в Main.vi следующее:
a. Tasking Open в самом начале при старте
b. Tasking Close в самом конце, если все параллельные циклы окончили свою работу
c. Подсоединяем все потоки так, чтобы они работали параллельно.
10.png
11. Добавляем кнопку и ивент exit. Используем Write All из библиотеки и глобальную команду exit, указав при этом что это глобальная команда с помощью флэга.
11.png
12. По идее уже всё должно работать. Теперь переходим к локальным командам для подприборов. Добавляем кнопку и ивент для запроса данных из подприбора SubVI 1.
12.png
12.png (7.41 КБ) 17539 просмотров
13. Здесь главное не перепутать кому предназначается команда и взять тот список локальных команд, который принадлежит именно этому получателю.
13.png
13.png (7.75 КБ) 17539 просмотров
14. Спрограммируем реакцию подприбора SubVI 1 на получение команды get data из Main.vi. Предположим мы будем генерировать случайное число и отправлять это число в Main.vi.
14.png
15. В нижнем цикле Main.vi, отвечающем за представление данных на лицевой панели (верхний мы используем для обработки ивентов) мы должны как то интерпретировать полученные данные. Это сделает Variant To Data из палитры Cluster->Variant. Тип данных мы знаем - это double.
15.png
16. Такую же процедуру проделаем с подприбором SubVI 2, но на этот раз возьмём строковой тип данных.
16.png
17 И в Main.vi так же указываем строковой тип данных.
17.png
Таким образом у нас получается организованная комуникация между параллельными потоками. О других видах средств общения (Notifier и User Event), поддерживаемых этой библиотекой я расскажу позднее, но принцип точно такой же что и с очередями.

Жду ваших отзывов :thank:
Вложения
Tasking2.zip
LV 8.2
(130.42 КБ) 644 скачивания
Tasking2 Example.zip
LV 8.6
(160.93 КБ) 599 скачиваний
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Ах да, совсем забыл. После того как вы распакуете архив и положите библиотеку в user.lib нужно во первых перестартонуть :labview: , а так же в Tools->Advanced->Edit Palette Set выбрать Place VI Content для темплейта. Тогда блок диаграмму темплейта можно будет сразу переносить в блок диаграмму прибора (как в случае с циклами и структурами).
Вложения
PlaceVIContent.png
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

И ещё наверное будет интересно знать, что команды можно отправлять не только в другие потоки, но и самому себе. Получается Queued State Machine, состояниями которой можно управлять как извне так и изнутри.
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Отклики? Предложения? Критика?
Аватара пользователя
FireFly

Activity Black
expert
expert
Сообщения: 1321
Зарегистрирован: 25 апр 2009, 08:58
Награды: 2
Версия LabVIEW: 2014
Откуда: Санкт-Петербург
Поблагодарили: 1 раз

Re: Tasking2 Library

Сообщение FireFly »

Ну лично для меня слишком унифицировано. Лично для меня удобнее сделать кластер всех очередей, для каждой очереди создать цикл, для каждого класса создать методы отправки эвента в очереди всех классов. Да это много однообразной работы, которая один в один повторяется из проекта в проект, но именно это помогает мне хорошо осознать то что я делаю, и работа с проектом идёт лучше.
Хотя, возможно, я так думаю пока проекты небольшие, а когда масштабы вырастут - воспользуюсь твоим способом.
Иногда лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Ну то же самое в этой библиотеке и сделано. Только ещё имеется удобный темплейт. Думаю многим сэкономит время да и приучит к однотипниму упорядоченному программированию.

По поводу унификации:
http://www.automationlabs.ru/forum/show ... 7#post6187

Идея зародилась уже аж:
12.04.2007, 00:51
Stkn
assistant
assistant
Сообщения: 128
Зарегистрирован: 25 янв 2009, 11:08
Версия LabVIEW: 2014

Re: Tasking2 Library

Сообщение Stkn »

eg
Не мог бы ты показать, как с помощью библиотеки организовать непрерывный сбор данных? Есть предположение, что нужно добавить цикл, из которого постоянно будет посылаться команда получить данные в другой цикл. Или есть более красивое решение?
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Да, я делаю по другому. Из какого то цикла посылается команда "старт" и в цикле сбора занным запускается внутренний цикл. Остановить этот внутренний цикл можно какой нибудь другой командой, например "стоп". Но вопрос в том как прочитать команду "стоп"? Для этого в библиотеке имеется :vi: Queue Status, который нужно поместить во внутренний цикл сбора данных. И заканчивать этот внутренний цикл по флэгу New Element Available.
Пример на картинках позже выложу.
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

И так, в SubVI2 добавлены две команды старт и стоп. По команде старт запускается внутренний цикл, который непрерывно собирает данные и отправляет их в Main.
Start.png
По любой команде внутренний цикл прерывается и выходит во внешний, где и считывается команда стоп и SubVI2 ничего не делает и ждёт другую команду.
Stop.png
Stop.png (6.68 КБ) 17352 просмотра
Ну а в Main мы просто добавили две кнопки, нажатие на которые отправляет команды в SubVI2. Так же в Main в нижнем цикле добавлен новый кейс, который показывает данные из внутреннего цикла сбора данных SubVI2.
Start Main.png
Stop Main.png
Stop Main.png (7.46 КБ) 17352 просмотра
Вложения
Tasking2 Example2.zip
(165.14 КБ) 443 скачивания
Stkn
assistant
assistant
Сообщения: 128
Зарегистрирован: 25 янв 2009, 11:08
Версия LabVIEW: 2014

Re: Tasking2 Library

Сообщение Stkn »

Спасибо. Библиотека понравилась. Попробую взять на вооружение. Ещё бы RT FIFO добавить, но там нужно указывать размер очереди при создании.
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Добавь, код открытый. У меня RT нет.
Библиотека сама по себе особой ценности не представляет, а вот идея такого стиля программирования очень распространена. Например вот:
http://expressionflow.com/2007/10/01/la ... hitecture/

В принципе существуют два способа организации программирования более сложных проектов в :labview: , это Queued State Machine и Functional Global Variables. Оба принципа используют параллельные циклы, но различные способы обмена данными между ними.

Я всего лишь постарался внести ясность в первый из них и успешно пользуюсь своей библиотекой.

Лично я так до конца и не понял как избежать Race Conditions во втором случае, но знаю, что это возможно, перенеся большую часть логики именно в FGV.
Sleepyhead
interested
interested
Сообщения: 2
Зарегистрирован: 27 июл 2010, 15:44
Версия LabVIEW: 2009
Контактная информация:

Re: Tasking2 Library

Сообщение Sleepyhead »

Спасибо за библиотеку. Возникло несколько вопросов. Используете ли вы подобный подход при работе с подключениями по TCP/IP, когда требуется прослушивать входящие сообщения используя связку create listener и wait on listener? Тут как и в случае с вложенным циклом возникает проблема останова потока, которую не получается решить тем же способом, так как Wait On Listener "висит" сам в себе при подаче таймаута "-1". На ум приходят два варинта: использование таймаутов или закрытие ссылки на listener извне. Первый не устравает, потому что хочется работать по событиям. А во втором не удается локализовать работу с сетью в одном потоке.

Еще пара технических вопросов. У меня стоит версия LabVIEW 2009 и некоторые VI, например Tasking2 Read Queue.vi выдают ошибку: Reentrant VIs can only have dynamic dispatch terminals if they share clones between instances. Т.е. приходится отказываться либо от хранения каких либо данных внутри VI, либо жертвовать переопределением функций в случае наследования(хотя обе возможности в контретной библиотеке как я вижу не используются).
Так же интересно почему функции записи Tasking2 Write ... .vi не оформлены как reentrant. Выходит, что независимые потоки могут блокировать выполнение друг друга в случае одновременной записи даже в разные очереди.
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Sleepyhead писал(а):Спасибо за библиотеку.
Спасибо за фидбэк!
Sleepyhead писал(а):Возникло несколько вопросов. Используете ли вы подобный подход при работе с подключениями по TCP/IP, когда требуется прослушивать входящие сообщения используя связку create listener и wait on listener?
Да, использую.
Sleepyhead писал(а):Тут как и в случае с вложенным циклом возникает проблема останова потока, которую не получается решить тем же способом, так как Wait On Listener "висит" сам в себе при подаче таймаута "-1". На ум приходят два варинта: использование таймаутов или закрытие ссылки на listener извне. Первый не устравает, потому что хочется работать по событиям. А во втором не удается локализовать работу с сетью в одном потоке.
Использую таймауты, так же как и в случае с VISA Read.
Sleepyhead писал(а):Еще пара технических вопросов. У меня стоит версия LabVIEW 2009 и некоторые VI, например Tasking2 Read Queue.vi выдают ошибку: Reentrant VIs can only have dynamic dispatch terminals if they share clones between instances. Т.е. приходится отказываться либо от хранения каких либо данных внутри VI, либо жертвовать переопределением функций в случае наследования(хотя обе возможности в контретной библиотеке как я вижу не используются).
Не думаю, что наследование пригодится, сделай их статичными. Хотя если добавить хранение каких либо данных внутрь, зачем? Ну а если что то нужно хранить, то я бы использовал кластер самого класса Tasking2.
Sleepyhead писал(а):Так же интересно почему функции записи Tasking2 Write ... .vi не оформлены как reentrant. Выходит, что независимые потоки могут блокировать выполнение друг друга в случае одновременной записи даже в разные очереди.
Не важно, т.к. размер очереди бесконечный, Write Queue зависать не собирается, то есть блокировка может произойти максимум на пару микро- милисекунд. Но если количество данных конечно огромное, то скорее стоит сделать их так же реинтрантными, думаю не помешает. Может быть я просто забыл об этом.
Sleepyhead
interested
interested
Сообщения: 2
Зарегистрирован: 27 июл 2010, 15:44
Версия LabVIEW: 2009
Контактная информация:

Re: Tasking2 Library

Сообщение Sleepyhead »

eg писал(а): Использую таймауты, так же как и в случае с VISA Read.
Т.е. во вложенном цикле происходит ожидание нового подключения в случае TCP/IP или распознаных данных/команды в случе VISA и дальнейшая обработка, а при таймауте новая итерация цикла?

Интересна дальнейшая судьба TCP/IP соединения. После подключения кого либо, напрашивается создание динамического потока через VI Server, который будет ожидать команд из сети, но как быть с отправкой данных в сеть из других потоков? Обычно я передавал connection ID основному управляющему циклу, а он хранил ее и передавал кому надо через глобальную переменную(неприятное решение, сделанное на скорую руку). Или же предпологается наличие заранее созданного потока, в котором регистрируются новые соединения, а он в свою очередь занимается мониторингом команд и отправкой данных в сеть?
Аватара пользователя
Eugen Graf

Activity Professionalism Silver Black
guru
guru
Сообщения: 6502
Зарегистрирован: 13 ноя 2007, 02:20
Награды: 4
Версия LabVIEW: 2009
Откуда: Saarbrücken
Контактная информация:

Re: Tasking2 Library

Сообщение Eugen Graf »

Вопрос понятен. Для обратной коммуникации в созданный поток передаётся класс Tasking, а для коммуникации с созданным потоком из "главного" создаётся массив очередей. Для каждого созданного потока в массив добавляется новая очередь.

Дополнительно сообщаю, что библиотека Tasking статична, поэтому в случае динамического, неограниченного и заранее неизвестного количества TCP соединений, я бы лучше использовал другой, более динамичный pattern, к примеру Observer или Publish Subscribe, что в принципе одно и то же.

Обязательно посмотри проект "Chat", там всё понятно.
Ответить

Вернуться в «Модели программирования»