PDA

Просмотр полной версии : Сетевые мьютексы



Devoter
04.08.2020, 10:43
В программировании есть такое понятие как Мьютекс (Mutex). Мьютексы, в основном, используются для того, чтоб контролировать доступ к данным в многопоточном приложении. Однако, и сетевые мьютексы - не новость. Протокол modbus подразумевает структуру сети вида master-slave, и хоть по tcp мастером может быть каждый, это не решает проблему контроля доступа к удаленным ресурсам.

Проблематика

В последнее время все чаще приходится работать с распределенными modbus-сетями. Рассмотрим пример: есть два сервера (master) и один модуль ввода (slave). Оба читают некоторые значения и могут изменять уставки этого модуля ввода. Теперь представим, что в некотором регистре находится битовая маска из уставок или, например счетчик. Сервер A делает уставку в бит 1 регистра уставок, а сервер B делает уставку в бит 2 того же регистра, но так как сервер B не знает, что сервер А только что изменил уставку, то он затирает новое значение бита 1.

Основных решений тут два:


В лоб: перед тем, как записать уставку - читаем текущее значение, добавляем свой бит, пишем уставку. Вероятность того, что сервер А в этот момент попытается изменить уставку крайне мала. С таким решением можно жить, но осадочек остается и некоторая вероятность возникновения неисправности по этой причине не будет давать спокойно спать по ночам;
Использовать сетевые мьютексы (подробно об этом ниже).


Есть разные виды мьютексов, но для наших задач достаточно самого простого:

Классический мьютекс

У классических мьютексов есть два состояния и два метода, соответственно: locked (метод lock()) и unlocked (метод unlock()). Принцип прост. При вызове метода lock() функция будет ждать, пока мьютекс не освободится, потом продолжит выполнение. unlock(), соответственно, освобождает мьютекс. Все действия по доступу к общим данным должны осуществляться между вызовами lock() и unlock().

Реализация в Modbus

Теперь можно рассмотреть простейшую реализацию сетевых мьютексов в Modbus. для мьютекса на slave-устройстве выделается один регистр под мьютекс, в который можно как писать, так и читать из него (для R/W-мьютекса требуется три регистра).

Алгоритм

Перед тем, как изменить уставку, сервер читает значение регистра с мьютексом, если регистр пустой, то он записывает туда свой ID. После этого можно снова прочитать значение регистра с мьютексом и убедиться, что в нем теперь записан нужный ID (lock()). Теперь можно производить запись уставки. После того, как все уставки сделаны - очищаем регистр с мьютексом (unlock()). Если при первом или втором чтении оказалось, что в регистре с мьютексом указан чужой ID, то нужно читать значение регистра до тех пор, пока он не будет обнулен.

Заключение

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

Отсюда мое предложение к компании ОВЕН: можно ли добавить в прошивки пустой holding регистр, который можно использовать для реализации сетевых мьютексов? Да, я в курсе, что есть протокол ОВЕН, DCOM и даже MQTT, который тут больше подходит, но они есть не во всех устройствах, особенно, если речь про RS485, с которыми можно работать через банальный шлюз, да и городить огород из кучи разных протоколов в одной сети, зачастую, неудобно.

Что скажете, участники форума? Возможно, я просто отстал от жизни и не знаю, что все уже украдено до нас, так что буду рад дельным советам и критике.

melky
04.08.2020, 10:53
Особенно про RS485, мастер в этой сети один, хоть можно и разнести во времени опрос с двух мастеров, тогда как раз два мастера между собой общаются, кто из них читает и пишет на данный момент.

Возникает вопрос, какие такие уставки будут писаться в модули в/в ? кому этот огород нужен ? а на ПЛК реализуется программой синхронизации.

Devoter
04.08.2020, 11:02
Для RS485 бывает так, что тот же модуль ввода или релейный модуль через шлюз пробрасывается в modbus tcp, а там мастеров сколь угодно много. Модуль ввода был взят для примера, чаще такое требуется для релейных модулей, но как пример, может статься так, что настройки модуля ввода могут меняться с разных мест.

А вот про программу синхронизации ПЛК, если можно, поподробней или ссылочкой.

melky
04.08.2020, 11:08
Не важно, сколько там мастеров при сквозном шлюзе, узкое место RS485, где связь сквозь шлюз к устройству только от ОДНОГО мастера (пусть он будет хоть трижды TCP) в один момент времени. Ни больше, ни меньше. Более умных шлюзов, которые отдают данные из регистров Modbus TCP я редко видел, и стоят они на порядок дороже. Где шлюз сам опрашивает RTU slave устройство и формирует карту регистров для TCP устройств.

А что тут подробнее ? если вам надо опрашивать устройство с двух ПЛК, выполните как вы и описали выше опрос, используя общую переменную между ПЛК. Один читает, второй ждет, и так далее. То есть организуйте мютекс сами, ну и не использовать Конфигурации, если речь идет о ПЛК Овен.

Devoter
04.08.2020, 12:33
Не важно, сколько там мастеров при сквозном шлюзе, узкое место RS485, где связь сквозь шлюз к устройству только от ОДНОГО мастера (пусть он будет хоть трижды TCP) в один момент времени. Ни больше, ни меньше. Более умных шлюзов, которые отдают данные из регистров Modbus TCP я редко видел, и стоят они на порядок дороже. Где шлюз сам опрашивает RTU slave устройство и формирует карту регистров для TCP устройств.

А что тут подробнее ? если вам надо опрашивать устройство с двух ПЛК, выполните как вы и описали выше опрос, используя общую переменную между ПЛК. Один читает, второй ждет, и так далее. То есть организуйте мютекс сами, ну и не использовать Конфигурации, если речь идет о ПЛК Овен.

Речь не об одном моменте времени. Возможно, не совсем корректно описал ситуацию. Положим, есть устройство, управляемое через релейный модуль, к примеру, которое управляется с двух разных точек через разные ПЛК, при этом, нам нужно сделать так, чтоб они работали независимо, то есть в любой момент времени один может быть недоступен, хотя согласование между контроллерами - действительно, логичное решение. Чтобы сеть не нагружать, постоянно опрашивая устройство, контроллер получает значение уставки только при запуске, а в остальное время просто запоминает - что он туда послал, то есть не ведет опрос и запись постоянно. И нельзя гарантировать, что не возникнет следующий сценарий:


контроллер A перед записью прочитал текущую уставку (0000 0000)
контроллер Б перед записью прочитал текущую уставку (0000 0000)
контроллер A обновил уставку (0001 0000)
контроллер Б обновил уставку (0000 0001, хотя должно быть 0001 0001, но ПЛК Б не прочитал обновленную уставку)


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


а) а чем пустой регистр будет отличаться от регистра с уставкой если лочить его будут мастера?
б) предлагаете вместо одного запроса более трех делать, а сети выдержат если трафик будет увеличен?
в) даже если используется модное слово мьютекс: а разве не затерётся бит, который записан при их использовании при такой интерпретации
г) может для промавтоматики и придумали ОРС сервера, чтоб клиенты не общались на прямую с модулями и не приходило в голову внедрять мьютексы

Не важно, будут ли его лочить в момент чтения/записи, об этом как раз ответ на предыдущее сообщение. Слово мьютекс не модное, термину больше 50 лет. Возможно, вы неверно поняли, опрашивать как раз постоянно не надо, так что 3 запроса подряд, вместо постоянной записи и чтения явно разгрузят сеть, а не загрузят, ну и OPC - это немного из другой оперы, применяется при другой схеме сети и для других задач. Суть в том, чтобы построить распределенную сеть на modbus.

Devoter
04.08.2020, 13:14
Решить, что регистр блокировки пуст он не сможет, потому что читает этот регистр, потом пишет в него, а потом снова проверяет, другое дело, что описанная вами ситуация с dead lock'ом имеет место быть в реальности и ее нужно решать отдельно. Для этого можно иметь возможность "насильной" записи в подобных случаях, тут уже от архитектуры самой автоматизированной системы зависит.

Я вопрос поднял с тем, чтобы расширить возможности имеющегося оборудования ОВЕН без особых затрат.

melky
04.08.2020, 19:20
Devoter еще раз, зачем вам в качестве синхронизации регистр КОНЕЧНОГО устройства ? используйте регистры ПЛК. Очередь опроса регулируйте между опрашивающими, а не через прокладку в виде регистра на опрашиваемом устройстве (конечном).

Вот именно, без особых затрат уже все решено, в ПЛК достаточно регистров так как это программируемое устройство. Нафик кто-то будет лепить горбатого для конечных устройств ?

kamalbajwa
17.02.2021, 09:02
In computer programming, a mutex (mutual exclusion object) is a program object that is created so that multiple program thread can take turns sharing the same resource, such as access to a file.

Алексей Геннадьевич
18.02.2021, 13:45
Я так понял что когда у автора темы заболит зуб он меняет сразу всю челюсть.

Для таких и нужны "мьютексы", "парадигмы" и прочие модные слова.

:)

По моему, автор что-то отказоустойчивое сделать хочет. Или какое-то другое отказоустойчивое решение.
Подобные решения автоматизации применяют в очень "весёлых" местах: Бхопал, Чернобыль и прочие опасные объекты.

Можете у Фёдорова в "справочнике инженера по АСУТП" почитать, если интересно.

kamalbajwa
23.02.2021, 13:20
I have a desktop application that runs on a network and every instance connects to the same database.

So, in this situation, how can I implement a mutex that works across all running instances that are connected to the same database?

In other words, I don't wan't that two+ instances to run the same function at the same time. If one is already running the function, the other instances shouldn't have access to it.

PS: Database transaction won't solve, because the function I wan't to mutex doesn't use the database. I've mentioned the database just because it can be used to exchange information across the running instances.

PS2: The function takes about ~30 minutes to complete, so if a second instance tries to run the same function I would like to display a nice message that it can't be performed right now because computer 'X' is already running that function.

PS3: The function has to be processed on the client machine, so I can't use stored procedures.

Алексей Геннадьевич
24.02.2021, 08:33
:)
... начинается железа и архитектуры данных, т.е. с проходной и разделения прав доступа к информации а не попыток раздать каждому водиле по мигалке/полосатой палке.

А что вы хотели от чистого программиста?
Понимание архитектуры системы на уровне "железа", причём со всеми задвижками-клапанами и датчиками?
Они же думают, что всё можно сделать чисто программой...


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

Вообще-то в модбасе и мастер только один должен быть.