Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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# 有没有办法知道FileSystemwatcher还有多少缓冲区?_C#_Multithreading_Events_Buffer_Filesystemwatcher - Fatal编程技术网

C# 有没有办法知道FileSystemwatcher还有多少缓冲区?

C# 有没有办法知道FileSystemwatcher还有多少缓冲区?,c#,multithreading,events,buffer,filesystemwatcher,C#,Multithreading,Events,Buffer,Filesystemwatcher,当我询问 fileSystemWatcher.InternalBufferSize 它将给出分配给观察者的总内部缓冲区大小。但我想知道(在调试期间)观察程序还剩下多少缓冲区大小,可以使用多少缓冲区大小,当我在事件处理程序方法中使用上述语句时(比如写操作),它总是给我分配给观察程序的总缓冲区大小。有没有办法获得缓冲区的剩余大小 其他问题: 从答案中可以明显看出,事件是在单独的线程上处理的,而不是在接收事件的线程上处理的。假设有许多并发事件发生在一个监视文件的观察者身上。我认为(如果我错了,请纠正

当我询问

fileSystemWatcher.InternalBufferSize
它将给出分配给观察者的总内部缓冲区大小。但我想知道(在调试期间)观察程序还剩下多少缓冲区大小,可以使用多少缓冲区大小,当我在事件处理程序方法中使用上述语句时(比如写操作),它总是给我分配给观察程序的总缓冲区大小。有没有办法获得缓冲区的剩余大小

其他问题:

从答案中可以明显看出,事件是在单独的线程上处理的,而不是在接收事件的线程上处理的。假设有许多并发事件发生在一个监视文件的观察者身上。我认为(如果我错了,请纠正我)接收事件信息的主线程将为每个事件生成一个新线程,并且事件处理将在不同的线程上进行。所以我想问:

  • 主线程会等待完成所有事件的处理吗
  • 哪个线程将清除与监视程序关联的内部缓冲区,以及何时清除
  • 我在很多地方都读到,处理程序方法应该花费尽可能少的时间,或者我们可以得到
    InternalBufferOverflow
    Exception。 那么,假设只有在处理handler方法的线程(我不能说是一个线程或所有线程,但想问您)已经处理了该方法时,才清理监视程序的内部缓冲区是否安全

  • 不,你不知道还有多少缓冲区

    它是一个隐藏在名为
    FSWAsyncResult
    的内部类中的实现细节。如果您掌握了该类的一个实例及其包含的缓冲区字节数组,您仍然无法可靠地回答还剩下多少空间,因为该字节数组仅充当调用的结果的保留内存

    在这个答案的底部可以找到一个精简的反向工程版本,它可以监视文件夹中的文件更改。它的逻辑和代码与您将在真正的FileSystemWatcher中找到的内容相匹配。我没有费心用它们的正确含义来替换这些神奇常数。它只是工作™. 不要忘记更改构建设置,因为代码会大量使用指针和本机结构。我去掉了所有的错误处理

    如果您遵循下面的代码,您会注意到只有一个地方创建了byte[]缓冲区,并且只发生一次。重复使用相同的缓冲区。阅读文档、博客,我了解到
    ReadDirectoryChangesW
    用于以I/O完成方式发出回调。这对托管世界没有多大关系,这只是另一个线程

    已在托管线程池线程上计划回调。有时,您会得到与以前相同的托管id,当它很忙时,您会得到几个。在该线程上执行
    CompletionStatusChanged
    。该方法负责处理当前字节缓冲区中存在的所有事件。请注意,我包含了一个
    sizeused
    变量,以便您可以看到缓冲区中存在的有效数据的实际大小。对于发现的每个事件,它都会同步地引发/调用事件的子记录器(在同一线程上也是如此)。完成后,它将使用刚刚处理的相同字节[]缓冲区再次调用
    Monitor
    。执行
    CompletionStatusChanged
    期间的任何文件更改都由操作系统保留,并在下次调用
    CompletionStatusChanged
    时发送

    tl;博士 以下是对您的问题的回答的摘要:

    。。。我想知道(在调试过程中)观察程序剩下多少缓冲区大小,可以使用多少缓冲区

    只使用了一个缓冲区,不知道使用了多少或剩下多少缓冲区是没有意义的。一旦调用EventHandler,缓冲区将重置并再次从0开始。当字节缓冲区无法处理更多事件时,它会引发异常

  • 主线程会等待完成所有事件的处理吗
  • 操作系统将通过IOCompletionPort发出异步回调,但这将显示为普通托管线程池线程。该线程将处理当前缓冲区中的所有事件并调用EventHandler

  • 哪个线程将清除与监视程序关联的内部缓冲区,以及何时清除
  • 执行CompletionStatusChanged方法的线程。请注意,在我的测试中,缓冲区从未被清除(如用零填充)。数据刚刚被覆盖

  • 我在很多地方都读到过,处理程序方法应该尽可能缩短时间,否则我们可以得到InternalBufferOverflow异常。那么,假设只有在处理handler方法的线程(我不能说是一个线程或所有线程,但想问您)已经处理了该方法时,才清理监视程序的内部缓冲区是否安全
  • 您应该尽可能缩短处理时间,因为只有一个线程将调用所有EventHandler,最后它必须再次调用
    ReadDirectoryChangesW
    。在此期间,它将跟踪文件更改。当这些filechange事件不适合缓冲区时,它将在下次调用completion方法时引发InternalBufferOverflow

    安装程序 一个简单的控制台应用程序,在等待事件时有一个ReadLine使其保持运行

    static object instance = new object(); // HACK
    static SafeFileHandle hndl; // holds our filehandle (directory in this case)
    
    static void Main(string[] args)
    {
    
        // the folder to watch
        hndl = NativeMethods.CreateFile(@"c:\temp\delete", 1, 7, IntPtr.Zero, 3, 1107296256, new SafeFileHandle(IntPtr.Zero, false));
        // this selects IO completion threads in the ThreadPool
        ThreadPool.BindHandle(hndl);
    
        // this starts the actual listening
        Monitor(new byte[4096]);
    
        Console.ReadLine();
    
    }
    
    班长 此方法负责创建本机结构和助手类的实例,作为IAsyncResult实现。
    此方法还调用
    ReadDirectoryChangesW
    ,并选择将其设置为异步完成的参数组合,以及IOCompletinPorts。有关这些选项的更多背景信息,请参阅

    完成状态已更改 一旦检测到文件更改,操作系统就会调用CompletionStatusChanged方法。在重叠结构中,我们将
    static unsafe void Monitor(byte[] buffer)
    {
    
        Overlapped overlapped = new Overlapped();
    
        // notice how the buffer goes here as instance member on AsyncResult.
        // Arrays are still Reference types.      
        overlapped.AsyncResult = new AsyncResult { buffer = buffer };
        // CompletionStatusChanged is the method that will be called
        // when filechanges are detected
        NativeOverlapped* statusChanged = overlapped.Pack(new IOCompletionCallback(CompletionStatusChanged), buffer);
    
        fixed (byte* ptr2 = buffer)
        {
            int num;
            // this where the magic starts
            NativeMethods.ReadDirectoryChangesW(hndl, 
              new HandleRef(instance, (IntPtr)((void*)ptr2)), 
              buffer.Length, 
              1, 
              (int)(NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Attributes), 
              out num, 
              statusChanged, 
              new HandleRef(null, IntPtr.Zero));
        }
    
    }
    
    // this gets called by a ThreadPool IO Completion thread
    static unsafe void CompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped* overlappedPointer)
        {
            var sb = new StringBuilder();
    
            Overlapped overlapped = Overlapped.Unpack(overlappedPointer);
            var result = (AsyncResult) overlapped.AsyncResult;
    
            var position = 0;
            int offset;
            int flags;
            int sizeused = 0;
            string file;
            // read the buffer,
            // that can contain multiple events
            do
            {
                fixed (byte* ptr = result.buffer)
                {
                    // process FILE_NOTIFY_INFORMATION
                    // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa364391(v=vs.85).aspx
                    offset = ((int*)ptr)[position / 4];
                    flags = ((int*)ptr + position / 4)[1];
                    int len = ((int*)ptr + position / 4)[2];
                    file = new string((char*)ptr + position / 2 + 6, 0, len / 2);
                    sizeused = position + len + 14; 
                }
                sb.AppendFormat("#thread {0},  event: {1}, {2}, {3}, {4}\r\n", Thread.CurrentThread.ManagedThreadId, position, offset, flags, file);
                // in the real FileSystemWatcher here the several events are raised
                // so that uses the same thread this code is on.
                position += offset;
            } while (offset != 0);
    
            // my own logging
            sb.AppendFormat(" === buffer used: {0} ==== ", sizeused);
    
            Console.WriteLine(sb);
    
            // start again, reusing the same buffer:
            Monitor(result.buffer);
        }
    }
    
    class AsyncResult : IAsyncResult
    {
        internal byte[] buffer;
        // default implementation of the interface left out
    
        // removed default implementation for brevity
    }
    
    static class NativeMethods
    {
        [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Auto)]
        public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, SafeFileHandle hTemplateFile);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public unsafe static extern bool ReadDirectoryChangesW(SafeFileHandle hDirectory, HandleRef lpBuffer, int nBufferLength, int bWatchSubtree, int dwNotifyFilter, out int lpBytesReturned, NativeOverlapped* overlappedPointer, HandleRef lpCompletionRoutine);
    }