非常简单的问题,但我只是想要一些澄清。我希望能够使用AutoResetEvent重新启动线程,因此我对我的AutoResetEvent调用以下方法序列。
setupEvent.Reset();
setupEvent.Set();我知道这很明显,但是MSDN并没有在他们的文档中声明Reset方法重新启动线程,只是将事件的状态设置为无信号。
更新:
是的,另一个线程正在等待WaitOne(),我假设当它被调用时,它将在它停止的确切位置恢复,这是我不想要的,我希望它从头开始。以下来自this valuable的示例说明了这一点:
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 -它非常复杂,但基本上我有一个运行FileSystemWatcher的CopyDetection线程来监控文件夹中是否有任何新文件被移动或复制到其中。我的第二个线程负责将该特定文件夹的结构复制到另一个文件夹中。因此,当复制/移动操作正在进行时,我的CopyDetection线程必须阻止该线程工作。当操作完成时,CopyDetection线程重新启动第二个线程,以便它可以使用新添加的文件重新复制文件夹结构。
更新3:
@SwDevMan81 -我实际上没有考虑到这一点,除了一个警告之外,这是可行的。在我的程序中,一旦复制过程完成,正在复制的源文件夹就会被清空。这就是为什么当新项目添加到源文件夹时,我必须阻止并重新启动第二个线程,这样它才有机会正确地重新解析文件夹的新结构。
为了解决这个问题,我正在考虑添加一个标志,表明删除源文件夹的内容是安全的。我想我可以把删除操作放在它自己的清理线程上。
@Jaroslav Jandek -我很抱歉,我以为一时兴起重新启动一个线程是一件很简单的事情。回答你的问题,我没有删除源文件夹,只删除它的内容,这是我的雇主的要求,不幸的是,我不能改变。正在移动源文件夹中的文件,但不是所有文件,仅移动其他进程正确验证的文件,其余文件必须清除,即清空源文件夹。此外,复制源文件夹结构的原因是,某些文件包含在必须保留在目标目录中的非常严格的子文件夹层次结构中。再次抱歉让事情变得复杂。所有这些机制都已经到位,经过测试,并且正在发挥作用,这就是为什么我觉得没有必要详细说明它们的原因。我只需要检测何时添加了新文件,这样我就可以在复制/移动操作正在进行时正确地停止其他进程,然后我就可以安全地复制源文件夹结构并恢复处理。
发布于 2011-03-11 02:32:55
所以线程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();
}发布于 2011-03-11 03:21:06
我认为这个例子阐明了(至少对我而言)重置事件是如何工作的:
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“或调用了WaitOne()时,对Reset()的下一次调用会阻塞。
发布于 2011-03-11 03:25:35
你只需要让它像其他线程一样循环即可。这就是你要找的东西吗?
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);
}
}
}
}
}https://stackoverflow.com/questions/5264007
复制相似问题