为什么我的IOCompetionCallback从未在我的IO完成端口上执行?

c#

最小可重现示例:

互操作文件

public static class Interop
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr CreateIoCompletionPort(
        [In] IntPtr fileHandle,
        [In] IntPtr existingCompletionPort,
        [In] UInt32 completionKey,
        [In] UInt32 numberOfConcurrentThreads);

    [DllImport("kernel32.dll")]
    public static extern UInt32 GetLastError();

    [DllImport("kernel32.dll")]
    public static unsafe extern bool GetQueuedCompletionStatus(
        [In] IntPtr completionPort,
        [Out] out UInt32 ptrBytesTransferred,
        [Out] out UInt32 ptrCompletionKey,
        [Out] NativeOverlapped** lpOverlapped,
        [In] UInt32 dwMilliseconds);

    [DllImport("kernel32.dll")]
    public static extern IntPtr CreateFile(
        [In] string fileName,
        [In] UInt32 dwDesiredAccess,
        [In] UInt32 dwShareMode,
        [In] IntPtr lpSecurityAttributes,
        [In] UInt32 dwCreationDisposition,
        [In] UInt32 dwFlagsAndAttributes,
        [In] IntPtr hTemplateFile);

    [DllImport("kernel32.dll")]
    public static unsafe extern bool ReadFile(
        [In] IntPtr hFile,
        [Out] byte[] lpBuffer,
        [In] uint maxBytesToRead,
        [Out] out UInt32 bytesActuallyRead,
        [In] NativeOverlapped* lpOverlapped);

    [DllImport("kernel32.dll")]
    public static extern bool PostQueuedCompletionStatus(
        [In] IntPtr completionPort,
        [In] UInt32 bytesTrasferred,
        [In] UInt32 completionKey,
        [In] IntPtr lpOverlapped);
}

程序.cs

class Program
{
    static unsafe void Main(string[] args)
    {
        // create completion port
        var completionPortHandle = Interop.CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, 0,  0);

        ThreadLogger.Log("Completion port handle: {0}", completionPortHandle);

        var completionPortThread = new Thread(() => new IOCompletionWorker().Start(completionPortHandle))
        {
            IsBackground = true
        };
        completionPortThread.Start();

        const uint Flags = 128 | (uint)1 << 30;

        var fileHandle = Interop.CreateFile("test.txt", (uint)1 << 31, 0, IntPtr.Zero, 3,
            /*FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED */ Flags,
            IntPtr.Zero);

        ThreadLogger.Log("File handle: {0}", fileHandle);

        Interop.CreateIoCompletionPort(
            fileHandle,
            completionPortHandle,
            (uint)fileHandle.ToInt64(), 
            0);

        ThreadLogger.Log("Associated file handle with completion port");

        var readBuffer = new byte[1024];

        uint bytesRead;

        var overlapped = new Overlapped 
        {
            AsyncResult = new FileReadAsyncResult()
            {
                ReadCallback = (bytesCount, buffer) =>
                    {
                        var contentRead = Encoding.UTF8.GetString(buffer, 0, (int)bytesCount);
                        ThreadLogger.Log(contentRead);
                    },
                Buffer = readBuffer
            } 
        };

        NativeOverlapped* nativeOverlapped = overlapped.UnsafePack((uint errorCode, uint numBytes, NativeOverlapped* pOVERLAP) =>
        {
            ThreadLogger.Log("Why am I not getting printed?");
        }, readBuffer);

        ThreadLogger.Log("Before read in main thread");

        Interop.ReadFile(fileHandle, readBuffer, (uint)readBuffer.Length, out bytesRead, nativeOverlapped);

        ThreadLogger.Log("After read in main thread");

        Console.ReadLine();
    }
}

文件读取异步结果.cs

class FileReadAsyncResult : IAsyncResult
{
    public bool IsCompleted { get; private set; }

    public WaitHandle AsyncWaitHandle { get; private set; }

    public object AsyncState { get; private set; }

    public bool CompletedSynchronously { get; private set; }

    public Action<uint, byte[]> ReadCallback { get; set; }

    public byte[] Buffer { get; set; }
}

IOCompletionWorker.cs

public class IOCompletionWorker
{ 
    public unsafe void Start(IntPtr completionPort)
    {
        while (true)
        {
            uint bytesRead;
            uint completionKey;
            NativeOverlapped* nativeOverlapped;

            ThreadLogger.Log("About to get queued completion status on {0}", completionPort);

            var result = Interop.GetQueuedCompletionStatus(
                completionPort, 
                out bytesRead,
                out completionKey,
                &nativeOverlapped, 
                uint.MaxValue);

            var overlapped = Overlapped.Unpack(nativeOverlapped);

            if (result)
            {
                var asyncResult = ((FileReadAsyncResult)overlapped.AsyncResult);
                asyncResult.ReadCallback(bytesRead, asyncResult.Buffer);
            }
            else
            {
                ThreadLogger.Log(Interop.GetLastError().ToString());
            }

            Overlapped.Free(nativeOverlapped);
        }
    }
}

我知道如果我使用Threadpool.BindHandle相应的文件句柄,我的回调将被运行 - 但我试图了解为什么当它在我自己的 IOCP 上注册时它没有被执行,一个线程正在等待完成包。(此外,线程池不知道如何处理我的自定义 AsyncResult - 那里的回调不会被执行。)

以上是为什么我的IOCompetionCallback从未在我的IO完成端口上执行?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>