Search code examples
c#.netprogramming-languages

AutoResetEvent Reset Method


super simple question, but I just wanted some clarification. I want to be able to restart a thread using AutoResetEvent, so I call the following sequence of methods to my AutoResetEvent.

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

I know it's really obvious, but MSDN doesn't state in their documentation that the Reset method restarts the thread, just that it sets the state of the event to non-signaled.

UPDATE:

Yes the other thread is waiting at WaitOne(), I'm assuming when it gets called it will resume at the exact point it left off, which is what I don't want, I want it to restart from the beginning. The following example from this valuable resource illustrates this:

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

If I understand this example correctly, notice how the Main thread will resume where it left off when the Work thread signals it, but in my case, I would want the Main thread to restart from the beginning.

UPDATE 2:

@Jaroslav Jandek - It's quite involved, but basically I have a CopyDetection thread that runs a FileSystemWatcher to monitor a folder for any new files that are moved or copied into it. My second thread is responsible for replicating the structure of that particular folder into another folder. So my CopyDetection thread has to block that thread from working while a copy/move operation is in progress. When the operation completes, the CopyDetection thread restarts the second thread so it can re-duplicate the folder structure with the newly added files.

UPDATE 3:

@SwDevMan81 - I actually didn't think about that and that would work save for one caveat. In my program, the source folder that is being duplicated is emptied once the duplication process is complete. That's why I have to block and restart the second thread when new items are added to the source folder, so it can have a chance to re-parse the folder's new structure properly.

To address this, I'm thinking of maybe adding a flag that signals that it is safe to delete the source folder's contents. Guess I could put the delete operation on it's own Cleanup thread.

@Jaroslav Jandek - My apologies, I thought it would be a simple matter to restart a thread on a whim. To answer your questions, I'm not deleting the source folder, only it's content, it's a requirement by my employer that unfortunately I cannot change. Files in the source folder are getting moved, but not all of them, only files that are properly validated by another process, the rest must be purged, i.e. the source folder is emptied. Also, the reason for replicating the source folder structure is that some of the files are contained within a very strict sub-folder hierarchy that must be preserved in the destination directory. Again sorry for making it complicated. All of these mechanisms are in place, have been tested and are working, which is why I didn't feel the need to elaborate on them. I only need to detect when new files are added so I may properly halt the other processes while the copy/move operation is in progress, then I can safely replicate the source folder structure and resume processing.


Solution

  • So thread 1 monitors and thread 2 replicates while other processes modify the monitored files.

    Concurrent file access aside, you can't continue replicating after a change. So a successful replication only occurs when there is long enough delay between modifications. Replication cannot be stopped immediately since you replicate in chunks.

    So the result of monitoring should be a command (file copy, file delete, file move, etc.). The result of a successful replication should be an execution of a command.

    Considering multiple operations can occur, you need a queue (or queued dictionary - to only perform 1 command on a file) of commands.

    // 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.
    }
    

    Now you may ask how to create a thread-safe query, but that probably belongs to another question (there are many implementations on the web).

    EDIT (queue-less version with whole dir replication - can be used with query): If you do not need multiple operations (eg. always replication the whole directory) and expect the replication to always finish or fail and cancel, you can do:

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