c# - 在多线程上下文中使用超时监视文件锁释放

标签 c# multithreading .net-4.0 .net-4.5

我正在使用 FileSystemWatcher 在文件到达我的系统文件夹时通知我。

有时,他们会带着锁(通过其他程序)到达

我想执行如下操作:

如果在 TIMEOUT 之后它们仍然被锁定,我们将忽略该文件 或者如果它们在我们处理文件的 TIMEOUT 内变为自由锁

我目前想出了这个解决方案,但想知道是否有任何其他方法可以实现它。

 lockedFilePaths = new List<string>();
 NoLockFilePaths = new List<string>();

 Watcher.Created += (sender, e) => WatcherHandler(e.FullPath);

 WatcherHandler(string FilePath)
 {
     CheckFileAccess(FilePath);
     if (NoLockFilePaths.Any())
     {
          //Process all file paths
     }
 }

 CheckFileAccess(string filepath)
 {
         // start a timer and invoke every say 10ms
         // log the locked time of the file.
         // compare the current time.
         // return null if TIMEOUT exceeds
         // or wait till the TIMEOUT and keep on checking the file access 
 }

问题是如何简单优化地实现CheckFileAccess?

我目前使用 System.Threading.Timer 每 1000 毫秒通知我一次,检查文件是否仍被锁定以及我的实现是否令我满意。寻找一些 super 简单实现的建议。

最佳答案

如果我必须做类似的事情,我会这样做:

public class Watcher
    {
        public readonly TimeSpan Timeout = TimeSpan.FromMinutes(10);

        private readonly FileSystemWatcher m_SystemWatcher;
        private readonly Queue<FileItem> m_Files;
        private readonly Thread m_Thread;
        private readonly object m_SyncObject = new object();
        public Watcher()
        {
            m_Files = new Queue<FileItem>();
            m_SystemWatcher = new FileSystemWatcher();
            m_SystemWatcher.Created += (sender, e) => WatcherHandler(e.FullPath);
            m_Thread = new Thread(ThreadProc)
                {
                    IsBackground = true
                };
            m_Thread.Start();
        }

        private void WatcherHandler(string fullPath)
        {
            lock (m_SyncObject)
            {
                m_Files.Enqueue(new FileItem(fullPath));
            }
        }

        private void ThreadProc()
        {
         while(true)//cancellation logic needed
         {
            FileItem item = null;
            lock (m_SyncObject)
            {
                if (m_Files.Count > 0)
                {
                    item = m_Files.Dequeue();
                }
            }

            if (item != null)
            {
                CheckAccessAndProcess(item);
            }
            else
            {
                SpinWait.SpinUntil(() => m_Files.Count > 0, 200);
            }
         }
        }

        private void CheckAccessAndProcess(FileItem item)
        {
            if (CheckAccess(item))
            {
                Process(item);
            }
            else
            {
                if (DateTime.Now - item.FirstCheck < Timeout)
                {
                    lock (m_SyncObject)
                    {
                        m_Files.Enqueue(item);
                    }
                }
            }
        }

        private bool CheckAccess(FileItem item)
        {
            if (IsFileLocked(item.Path))
            {
                if (item.FirstCheck == DateTime.MinValue)
                {
                    item.SetFirstCheckDateTime(DateTime.Now);
                }
                return false;
            }

            return true;
        }

        private void Process(FileItem item)
        {
            //Do process stuff
        }

        private bool IsFileLocked(string file)
        {
            FileStream stream = null;
            var fileInfo = new FileInfo(file);

            try
            {
                stream = fileInfo.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException)
            {
                return true;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }
            return false;
        }
    }

    public class FileItem
    {
        public FileItem(string path)
        {
            Path = path;
            FirstCheck = DateTime.MinValue;
        }

        public string Path { get; private set; }
        public DateTime FirstCheck { get; private set; }

        public void SetFirstCheckDateTime(DateTime now)
        {
            FirstCheck = now;
        }
    }

从 CheckAccess 和 IsFileLocked 中,您可以返回 FileStream 对象,以确保不会从 CheckAccess 和 Process 调用之间的另一个进程获取文件句柄;

关于c# - 在多线程上下文中使用超时监视文件锁释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17161091/

相关文章:

c# - 在 .NET Framework 2 中播放 PCM 数据?

windows - windows线程溢出时如何查看当前栈大小

dns - .NET 4.0 上的 System.Net.Dns.GetHostEntry(dnsServer) 问题

c# - 如何将图像旋转任意度数?

c# - 无法使用 C# 访问 linq 属性

c# - 我可以在 WPF 中即时创建图标吗?

java - Android:蓝牙监听线程正在阻塞 UI 线程

java - 如何在 JFrame 退出时运行终止命令?

c# - BlockingCollection 最大大小

c# - 从 Silverlight 调用 WCF 服务