// в OnChange выставлять флаг что нужно обновлять SharedData - далее в одновном цикле анализировать флаг
 private void Dependency_OnChange(object sender, OracleNotificationEventArgs e)
 {
     StringBuilder Tables = new StringBuilder();
       foreach (var Name in e.ResourceNames)
       {
     if (Name.ToUpper().Contains(NotifierCheckTable))
     {
       NotifierCheckState = NotifierCheckStates.CheckSuccess;
     }
     else
     {
       Tables.AppendFormat("{0} ", Name);
       Interlocked.Increment(ref Notifications);
     }
       }
       if (Notifications > 0)
       {
     EventHandle.Set(); // wake up load thread
     Log.Message("Уведомление об изменениях: " + Tables);
       }
 }
 private void LoadThreadExecute()
 {
     ChangeStatus("Started");
       try
       {
     while (!LoadThreadTerminated)
     {
       ShowFullStatus("Sleeping...");
       EventHandle.WaitOne(); // спим до получения уведомления о событии
       ShowFullStatus("Loading new generation...");
       try
       {
     if (Notifications > 0) Log.Message("Обнаружены изменения в БД...");
     Notifications = 0; // обнуляем счётчик уведомлений перед рестартом, т.к. уведомление может прийти и после рестарта. Атомарная операция
     if (NotifierCheckState == NotifierCheckStates.CheckFailed) // после этого всё равно загружаем новые данные - вдруг мы что-то пропустили, пока система уведомлений не работала
     {
       Log.Message("Требуется перезапуск подсистемы слежения за изменениями БД!");
       try
       {
         RestartNotifier(); // перезапускаем нотификатор, если он не прошел проверку, после чего устанавливаем состояние Idle
         NotifierCheckState = NotifierCheckStates.WasRestarted;
       }
       catch (Exception e)
       {
         if (e is ThreadAbortException || e is ThreadInterruptedException) throw; // для выхода в родительский try...
         Log.Message("Ошибка в цикле ожидания при перезапуске подсистемы отслеживания: {0}", e.Message);
       }
     }
     Load(); // после перезапуска нотификатора начинаем заново грузить ОРД
       }
       catch (Exception e)
       {
     if (e is ThreadAbortException || e is ThreadInterruptedException) return;
     else Log.Message("Ошибка цикла ожидания момента обновления ОРД: {0}\n{1}", e.Message, e.StackTrace);
       }
     }
       }
       catch (Exception e)
       {
     if (e is ThreadAbortException || e is ThreadInterruptedException)  return;
     else Log.Message("Ошибка потока загрузки ОРД: {0}\n{1}", e.Message, e.StackTrace);
       }
 }
        private void CheckNotifier()
        {
            try
              {
            NotifierCheckState = NotifierCheckStates.Idle;
            while (true)
            {
              //Log.Message("Check Notifier state: {0}", NotifierCheckState);
              switch (NotifierCheckState)
              {
            case NotifierCheckStates.Idle:
              var StartWaitTime = DateTime.Now;
              ShowFullStatus("Sleeping...");
              while (DateTime.Now - StartWaitTime <= CheckChangeNotifierInterval)
              {
                Thread.Sleep(1000);
                if (NotifierCheckState != NotifierCheckStates.Idle)
                  break;
              }
              if (NotifierCheckState != NotifierCheckStates.CheckSuccess)
                NotifierCheckState = NotifierCheckStates.StartCheck;
              break;
            case NotifierCheckStates.StartCheck:
              using (var c = new OracleConnection(ConnectionString))
              {
                c.AutoCommit = false;
                c.Open();

                NotifierCheckState = NotifierCheckStates.CheckStarted; // must be set before, because notification can come right away
                NotifierCheckStartTime = DateTime.Now;

                int RowsUpdated = OraQuery.ExecuteNonQuery(c, string.Format("update {0} set id = id + 1 where rownum = 1", NotifierCheckTable));
                if (RowsUpdated > 0) c.Commit(); else c.Rollback();
              }
              break;
            case NotifierCheckStates.CheckStarted: // started, in processes
              if (DateTime.Now - NotifierCheckStartTime >= CheckChangeNotifierTimeout) // if no answer after starting
                NotifierCheckState = NotifierCheckStates.CheckFailed;
              else
                Thread.Sleep(1000);
              break;
            case NotifierCheckStates.CheckSuccess:
            case NotifierCheckStates.WasRestarted:
              NotifierCheckState = NotifierCheckStates.Idle;
              break;
            case NotifierCheckStates.CheckFailed: // need restart
              Log.Message("Check Notifier state: {0}", NotifierCheckState); // It is important state
              EventHandle.Set(); // wake up thread for restart
              Thread.Sleep(1000);
              break;
            default:
              Log.Message("Unknown status: {0}", NotifierCheckState);
              break;
              }
            }
              }
              catch (Exception e)
              {
            if (e is ThreadAbortException || e is ThreadInterruptedException) return;
            else Log.Message("Ошибка потока проверки нотификатора: {0}\n{1}", e.Message, e.StackTrace);
              }
        }