"Критическая секция": разграничение доступа к ресурсу
В этом выпуске я расскажу о способе организации "критической секции" в советнике.
Дело в том, что если в момент выполнения этих функций будет осуществлен доступ к массивам данных, хранимых в глобальных переменных, из нескольких советников одновременно, то результат будет непредсказуемым и в большинстве случаев данные будут испорчены.
Для того, чтобы избежать этого, мы создадим объект "критическая секция", который может находиться в двух состояниях:
- "зеленый свет" (-1); и
- "красный свет" (1).
В каждый конкретный момент только один советник может получить доступ к данным. Пока советник получает данные, будет гореть "красный свет" и другие советники будут ждать "зеленового света". Если горит "зеленый свет", то дорога свободна, т.к. никто в данный момент к данным не обращается.
Напишем две функции:
- Lock() - вызываем ее перед началом работы с ресурсом. Функция ждет "зеленового света" и меняет его на "красный".
- Unlock() - обязательно вызываем ее после окончания работы с ресурсом, чтобы снова зажечь "зеленый свет".
Вот исходный код этих функций:
//+------------------------------------------------------------------+ //| Lock() | //| | //| Возвращает: | //| 0 - если "критическая секция" успешно | //| заблокирована | //| 1 - в случае ошибки | //| 2 - эксперт остановлен | //| 3 - по таймауту (слишком долго ждали) | //+------------------------------------------------------------------+ int Lock(string GlobVarName, int timeout = 0) { string critical_section = GlobVarName+"Lock";
// проверим, существует ли переменная critical_section if (!GlobalVariableCheck(critical_section)) { if (GetLastError()!=0) return(1);
// переменная не существует, создадим ее if (GlobalVariableSet(critical_section, -1.0)==0) return(1); // переменная создана }
int StartTime = GetTickCount();
// ждем "зеленового света" while (true) { // проверить, не загорелся ли "зеленый свет" if (GlobalVariableGet(critical_section)==-1.0) { // "зеленый свет" загорелся, зажигаем "красный свет" if (GlobalVariableSetOnCondition(critical_section, 1.0, -1.0)) return(0);
// нас опередили, поэтому ждем "зеленового света" }
// проверим, не остановлен ли эксперт if (IsStopped()) return(2);
// таймаут не истек? if (timeout!=0) { if ((GetTickCount()-StartTime)>timeout*1000) return(3); }
// спим 0.1 секунды Sleep(100); } }
//+------------------------------------------------------------------+ //| Unlock() | //| | //| Возвращает: | //| 0 - если "критическая секция" успешно | //| разблокирована | //| 1 - в случае ошибки | //| 2 - эксперт остановлен | //| 3 - по таймауту (слишком долго ждали) | //+------------------------------------------------------------------+ int Unlock(string GlobVarName, int timeout = 0) { string critical_section = GlobVarName+"Lock";
// проверим, существует ли переменная critical_section if (!GlobalVariableCheck(critical_section)) { if (GetLastError()!=0) return(1);
// переменная не существует, создадим ее if (GlobalVariableSet(critical_section, -1.0)==0) return(1);
// переменная создана, поэтому выходим return(-1.0); }
int StartTime = GetTickCount();
// бесконечный цикл while (true) { // пытаемся установить "зеленый свет" if (GlobalVariableSetOnCondition(critical_section, -1.0, 1.0)) return(0);
// проверим, не остановлен ли эксперт if (IsStopped()) return(2);
// таймаут не истек? if (timeout!=0) { if ((GetTickCount()-StartTime)>timeout*1000) return(3); }
// спим 0.1 секунды Sleep(100); } }
В следующем выпуске я разберу код этих функций.
Все статьи по теме "Пишем советников для MetaTrader 4".
- Механическая торговая система - миф или реальность?
- С чего начать при написании советника:
- Создаем нового советника - Настраиваем параметры. - Язык MetaQuotes Language 4: