Метод сброса AutoResetEvent - PullRequest
4 голосов
/ 10 марта 2011

супер простой вопрос, но я просто хотел уточнить.Я хочу иметь возможность перезапустить поток с помощью AutoResetEvent, поэтому я вызываю следующую последовательность методов для моего AutoResetEvent.

setupEvent.Reset();                   
setupEvent.Set();

Я знаю, что это действительно очевидно, но MSDN в своей документации не заявляет, чтоМетод Reset перезапускает поток, просто он устанавливает состояние события как не сигнализированное.

ОБНОВЛЕНИЕ:

Да, другой поток ожидает в WaitOne (), я предполагаю, когдаон вызывается, он возобновляется в том месте, где остановился, чего я не хочу, я хочу, чтобы он перезапустился с самого начала.Следующий пример из этого ценного ресурса иллюстрирует это:

static void Main()
  {
    new Thread (Work).Start();

    _ready.WaitOne();                  // First wait until worker is ready
    lock (_locker) _message = "ooo";
    _go.Set();                         // Tell worker to go

    _ready.WaitOne();
    lock (_locker) _message = "ahhh";  // Give the worker another message
    _go.Set();
    _ready.WaitOne();
    lock (_locker) _message = null;    // Signal the worker to exit
    _go.Set();
  }

  static void Work()
  {
    while (true)
    {
      _ready.Set();                          // Indicate that we're ready
      _go.WaitOne();                         // Wait to be kicked off...
      lock (_locker)
      {
        if (_message == null) return;        // Gracefully exit
        Console.WriteLine (_message);
      }
    }
  }

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

ОБНОВЛЕНИЕ 2:

@ Ярослав Джандек - Это довольно сложный процесс, но в основном у меня есть поток CopyDetection, который выполняетFileSystemWatcher для мониторинга папки на наличие новых файлов, которые перемещаются или копируются в нее.Мой второй поток отвечает за репликацию структуры этой конкретной папки в другую папку.Таким образом, мой поток CopyDetection должен блокировать работу этого потока во время выполнения операции копирования / перемещения.Когда операция завершается, поток CopyDetection перезапускает второй поток, чтобы он мог повторно продублировать структуру папок с вновь добавленными файлами.

ОБНОВЛЕНИЕ 3:

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

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

@ Jaroslav Jandek - Мои извинения, я думал, что было бы просто перезапустить поток по своей прихоти.Чтобы ответить на ваши вопросы, я не удаляю исходную папку, только ее содержимое, это требование моего работодателя, которое, к сожалению, я не могу изменить.Файлы в исходной папке перемещаются, но не все, только файлы, которые были надлежащим образом проверены другим процессом, остальные должны быть очищены, т.е. исходная папка очищена.Кроме того, причина репликации структуры исходных папок заключается в том, что некоторые файлы содержатся в очень строгой иерархии подпапок, которая должна сохраняться в целевом каталоге.Снова извините за усложнение.Все эти механизмы внедрены, были протестированы и работают, поэтому я не чувствовал необходимости подробно останавливаться на них.Мне нужно только определять, когда добавляются новые файлы, чтобы я мог надлежащим образом остановить другие процессы во время выполнения операции копирования / перемещения, а затем безопасно сменить структуру исходной папки и возобновить обработку.

Ответы [ 3 ]

1 голос
/ 10 марта 2011

Таким образом, поток 1 отслеживает, а поток 2 реплицируется, в то время как другие процессы изменяют отслеживаемые файлы.

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

Таким образом, результатом мониторинга должна быть команда (копирование файла, удаление файла, перемещение файла и т. Д.). Результатом успешной репликации должно стать выполнение команды.

Учитывая, что может произойти несколько операций, вам нужна очередь (или поставленный в очередь словарь - для выполнения только одной команды над файлом) команд.

// T1:
somethingChanged(string path, CT commandType)
{
  commandQueue.AddCommand(path, commandType);
}

// T2:
while (whatever)
{
  var command = commandQueue.Peek();
  if (command.Execute()) commandQueue.Remove();
  else // operation failed, do what you like.
}

Теперь вы можете спросить, как создать потокобезопасный запрос, но это, вероятно, относится к другому вопросу (в Интернете есть много реализаций).

РЕДАКТИРОВАТЬ (версия без очереди с полной репликацией dir - может использоваться с запросом): Если вам не нужны множественные операции (например, всегда репликация всего каталога) и вы ожидаете, что репликация всегда завершится или завершится с ошибкой и отменится, вы можете сделать:

private volatile bool shouldStop = true;

// T1:
directoryChanged()
{
  // StopReplicating
  shouldStop = true;
  workerReady.WaitOne(); // Wait for the worker to stop replicating.

  // StartReplicating
  shouldStop = false;
  replicationStarter.Set();
}

// T2:
while (whatever)
{
  replicationStarter.WaitOne();

  ... // prepare, throw some shouldStops so worker does not have to work too much.

  if (!shouldStop)
  {
    foreach (var file in files)
    {
      if (shouldStop) break;

      // Copy the file or whatever.
    }
  }

  workerReady.Set();
}
0 голосов
/ 10 марта 2011

Вам просто нужно сделать цикл таким же, как это делает другой поток.Это то, что вы ищете?

   class Program
   {
      static AutoResetEvent _ready = new AutoResetEvent(false);
      static AutoResetEvent _go = new AutoResetEvent(false);
      static Object _locker = new Object();
      static string _message = "Start";

      static AutoResetEvent _exitClient = new AutoResetEvent(false);
      static AutoResetEvent _exitWork = new AutoResetEvent(false);

      static void Main()
      {
         new Thread(Work).Start();
         new Thread(Client).Start();

         Thread.Sleep(3000); // Run for 3 seconds then finish up

         _exitClient.Set();
         _exitWork.Set();
         _ready.Set(); // Make sure were not blocking still
         _go.Set();
      }

      static void Client()
      {
         List<string> messages = new List<string>() { "ooo", "ahhh", null };
         int i = 0;
         while (!_exitClient.WaitOne(0))       // Gracefully exit if triggered
         {
            _ready.WaitOne();                  // First wait until worker is ready
            lock (_locker) _message = messages[i++];
            _go.Set();                         // Tell worker to go
            if (i == 3) { i = 0; }
         }
      }

      static void Work()
      {
         while (!_exitWork.WaitOne(0))             // Gracefully exit if triggered
         {
            _ready.Set();                          // Indicate that we're ready
            _go.WaitOne();                         // Wait to be kicked off...
            lock (_locker)
            {
               if (_message != null)
               {
                  Console.WriteLine(_message);
               }
            }
         }
      }
   }
0 голосов
/ 10 марта 2011

Я думаю, что этот пример проясняет (для меня в любом случае), как работают события сброса:

var resetEvent = new ManualResetEvent(false);
var myclass = new MyAsyncClass();
myclass.MethodFinished += delegate
{
  resetEvent.Set();
};
myclass.StartAsyncMethod();
resetEvent.WaitOne(); //We want to wait until the event fires to go on

Предположим, что MyAsyncClass запускает метод в другом потоке и запускает событие, когда завершено.

Это в основном превращает асинхронный «StartAsyncMethod» в синхронный.Много раз я нахожу реальный пример более полезным.

Основное различие между AutoResetEvent и ManualResetEvent состоит в том, что использование AutoResetEvent не требует от вас вызова Reset (), но автоматически устанавливает состояние «false»,Следующий вызов WaitOne () блокируется, когда состояние равно «false» или вызывается Reset ().

...