Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 自动复位法_C#_.net_Programming Languages - Fatal编程技术网

C# 自动复位法

C# 自动复位法,c#,.net,programming-languages,C#,.net,Programming Languages,超级简单的问题,但我只是想澄清一下。我希望能够使用AutoResetEvent重新启动线程,因此我将以下方法序列调用到AutoResetEvent setupEvent.Reset(); setupEvent.Set(); 我知道这很明显,但是MSDN在他们的文档中没有声明重置方法重新启动线程,只是将事件的状态设置为无信号 更新: 是的,另一个线程正在等待WaitOne(),我假设当它被调用时,它将在它离开的确切位置恢复,这是我不想要的,我希望它从一开始就

超级简单的问题,但我只是想澄清一下。我希望能够使用AutoResetEvent重新启动线程,因此我将以下方法序列调用到AutoResetEvent

setupEvent.Reset();                   
setupEvent.Set();
我知道这很明显,但是MSDN在他们的文档中没有声明重置方法重新启动线程,只是将事件的状态设置为无信号

更新:

是的,另一个线程正在等待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:

@Jaroslav Jandek-这相当复杂,但基本上我有一个CopyDetection线程,它运行一个FileSystemWatcher来监视文件夹中移动或复制到其中的任何新文件。我的第二个线程负责将该特定文件夹的结构复制到另一个文件夹中。因此,当复制/移动操作正在进行时,我的CopyDetection线程必须阻止该线程工作。操作完成后,CopyDetection线程将重新启动第二个线程,以便使用新添加的文件重新复制文件夹结构

更新3:

@SwDevMan81-我实际上没有想到这一点,除了一个警告外,这是可行的。在我的程序中,复制过程完成后,将清空正在复制的源文件夹。这就是为什么在将新项目添加到源文件夹时,我必须阻止并重新启动第二个线程,以便它有机会正确地重新解析文件夹的新结构

为了解决这个问题,我考虑添加一个标志,表明删除源文件夹的内容是安全的。我想我可以把删除操作放在它自己的清理线程上


@Jaroslav Jandek-我很抱歉,我认为突发奇想重启一个线程将是一件简单的事情。为了回答你的问题,我没有删除源文件夹,只是删除了它的内容,这是我的雇主的要求,很遗憾,我不能更改。源文件夹中的文件正在被移动,但不是全部,只有经过另一个进程正确验证的文件,其余文件必须被清除,即源文件夹被清空。另外,复制源文件夹结构的原因是,某些文件包含在非常严格的子文件夹层次结构中,必须保留在目标目录中。再次抱歉让事情复杂化了。所有这些机制都已经到位,已经过测试并且正在发挥作用,这就是为什么我觉得没有必要详细阐述它们。我只需要检测何时添加了新文件,这样我就可以在复制/移动操作进行时正确停止其他进程,然后我就可以安全地复制源文件夹结构并恢复处理。

因此线程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.
}
现在您可能会问如何创建线程安全查询,但这可能属于另一个问题(web上有许多实现)

编辑(带有全目录复制的无队列版本-可与查询一起使用): 如果不需要多个操作(例如,始终复制整个目录),并且希望复制始终完成或失败并取消,则可以执行以下操作:

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();
}

我认为这个例子(对我来说)阐明了重置事件是如何工作的:

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”。当状态为“false”或已调用Reset()时,对WaitOne()的下一次调用将被阻塞。

您只需像其他线程一样使其循环即可。这就是你要找的吗

   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);
               }
            }
         }
      }
   }
类程序
{
静态自动恢复事件_ready=新自动恢复事件(false);
静态自动重置事件_go=新自动重置事件(false);
静态对象_locker=新对象();
静态字符串_message=“Start”;
静态自动恢复事件_exitClient=新自动恢复事件(false);
静态自动重置事件_exitWork=新自动重置事件(false);
静态void Main()
{
新线程(工作).Start();
新线程(Client.Start();
Thread.Sleep(3000);//运行3秒钟,然后结束
_exitClient.Set();
_exitWork.Set();
_ready.Set();//确保您没有仍然阻塞
_go.Set();
}
静态void客户端()
{
列表消息=新列表(){“ooo”,“ahhh”,null};
int i=0;
while(!\u exitClient.WaitOne(0))//在触发时优雅地退出
{
_ready.WaitOne();//首先等待工作进程准备就绪
锁(_locker)_message=messages[i++];
_go.Set();//告诉工人去
如果(i)