一次读一个文件

时间:2014-01-24 08:34:26

标签: c# multithreading locking

我有以下代码来查找目录中的新文件:

            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = @"C:\temp\Dir1\";
            watcher.Created += new FileSystemEventHandler(OnChanged);
            watcher.EnableRaisingEvents = true;

OnChanged事件处理程序:

            public void OnChanged(object source, FileSystemEventArgs e)
            {           
                 Thread t = new Thread(readFile);
                 t.Start(e.FullPath);
            }

readFile线程方法:

            public void readFile(){
                 FSReader vsfr = new FSReader((string)path);
                 while (vsfr.EndOfStream == false)
                 {
                    PrintLine(vsfr.ReadLine());
                 }
                 vsfr.Close();
            }

因此,每次创建新文件时,readFile线程都会读取它。当第一个文件被读取而第二个文件开始被另一个线程读取时,会出现问题。

我需要的是第一个线程在第二个线程打开时终止所以一次只运行一个线程来读取单个文件。我知道我需要使用锁和事件来实现这一目标。

当我在lock方法上使用readFile时,我得到了一次运行单个线程的所需结果,但我还是需要一种方法来告诉前一个线程关闭,当新线程打开。我怎么能这样做?

任何提示?谢谢。

2 个答案:

答案 0 :(得分:1)

听起来很简单,只需在阅读文件和一些简单的取消时添加锁定

string _path;
Thread
object _lock = new object();
volatile bool _running;
volatile bool _cancel;

public void OnChanged(object source, FileSystemEventArgs e)
{   
    // waiting
    while(_running)
    {
        _cancel = true;
        Thread.Sleep(0);
    }
    // start new thread
    _cancel = false;
    _path = e.FullPath;
    (new Thread(ReadFile)).Start();
}

public void ReadFile()
{
    lock(_lock)
    {
        _running = true;
        using(var reader = new FSReader(_path))
            while (!reader.EndOfStream)
            {
                if(_cancel)
                    break;
                PrintLine(reader.ReadLine());
            }
        _running = false;
    }
}

我认为,您希望一次只有 1个线程

创建新线程时,您必须检查它是否已经在运行,如果是,则设置取消并等待它完成。

可以保留Thread个实例并检查IsAlive,而不是使用_running

您可以使用Task代替Thread。您可以使用ManualResetEvent来避免需要睡眠,但在这种情况下Sleeps对我来说无害。

修改

让我们玩吧

volatile bool _cancel;
Mutex _mutext = new Mutex(false);

public void OnChanged(object source, FileSystemEventArgs e)
{
    _cancel = true;
    _mutex.WaitOne();
    // start new thread
    _cancel = false;
    _mutex.ReleaseMutex();
    (new Thread(ReadFile)).Start(e.FullPath);
}

public void ReadFile(string path)
{
    _mutex.WaitOne();
    using(var reader = new FSReader(path))
        while (!reader.EndOfStream)
        {
            if(_cancel)
                break;
            PrintLine(reader.ReadLine());
        }
    _mutex.ReleaseMutex();
}

现在我们正在使用Mutex来确保没有新线程将被启动,直到现有(如果有)将完成其工作。不需要lock(互斥体完成所有工作)。

修改

实际上,有一个微不足道的机会,如果{/ 1}}在线程获取互斥锁所有权之前将其称为(理论上可能),那么我们遇到了麻烦。

解决方案是实现在线程和事件之间等待的 ping-pong (两个互斥,或者可能是其他一些同步原语)。

答案 1 :(得分:1)

我会按照这些方针做点什么。显然添加自己的锁/同步。

while (vsfr.EndOfStream == false)
{
  if (cancelThread)
  {
     vsfr.Close()
     return;
  }
  PrintLine(vsfr.ReadLine());
}

public void OnChanged(object source, FileSystemEventArgs e)
{           
   Thread t = new Thread(readFile);
   //If a thread is running, set the cancellation flag = true
   //If you have some class-level reference to the running thread, you can then wait for it to .Join()
   //Set cancellation flag back to false
   t.Start(e.FullPath);
}