home

Расскажем о способе организации «критической секции» в советнике.

Дело в том, что если в момент выполнения этих функций будет осуществлен доступ к массивам данных, хранимых в глобальных переменных, из нескольких советников одновременно, то результат будет непредсказуемым и в большинстве случаев данные будут испорчены.

Для того, чтобы избежать этого, мы создадим объект «критическая секция», который может находиться в двух состояниях:

  • «зеленый свет» (-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);
}
}