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开始。当字节缓冲区无法处理更多事件时,它会引发异常
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);
}