gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 11:34:52 26 4
gpt4 key购买 nike

最小可重现示例:
互操作文件

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 - 那里的回调不会被执行。)

最佳答案

IO 完成端口的工作方式是创建一个完成端口,将它绑定(bind)到一个文件句柄,然后启动 n 个 IO 完成端口线程,等待 GetQueuedCompletionStatus 在这个阻塞调用中返回。
您在代码中提到的回调不是 IO Completion 端口基础结构的一部分。它是 .NET 线程池的一项服务,您可以在其中调用 ThreadPool.BindHandle(SafeHandle osHandle),它会在此句柄的 IO 完成完成时回调您。
但是,如果您自己做所有事情,那么 .NET 线程池服务将无法使用。
调用调用堆栈是

IOCompletionPort.Sample!IOCompletionPort.Sample.Program+<>c.<Main>b__0_0(UInt32, UInt32, System.Threading.NativeOverlapped*)+0x45[c:\Source\async-io-talk\src\IOCompletionPorts\IOCompletionPort.Sample\Program.cs @ 63]
mscorlib!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)+0x84
clr!CallDescrWorkerInternal+0x83
clr!CallDescrWorkerWithHandler+0x4e
clr!DispatchCallSimple+0x67
clr!BindIoCompletionCallBack_Worker+0xee
clr!ManagedThreadBase_DispatchInner+0x40
clr!ManagedThreadBase_DispatchMiddle+0x6c
clr!ManagedThreadBase_DispatchOuter+0x4c
clr!ManagedThreadBase_FullTransitionWithAD+0x2f
clr!BindIoCompletionCallbackStubEx+0xb9
clr!BindIoCompletionCallbackStub+0x9
clr!ThreadpoolMgr::CompletionPortThreadStart+0x604
clr!Thread::intermediateThreadProc+0x8b
KERNEL32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21
当 IO 完成完成时,在另一个线程上调用 BindIoCompletionCallbackStub 方法
FCIMPL1(FC_BOOL_RET, ThreadPoolNative::CorPostQueuedCompletionStatus, LPOVERLAPPED lpOverlapped)
{
FCALL_CONTRACT;

OVERLAPPEDDATAREF overlapped = ObjectToOVERLAPPEDDATAREF(OverlappedDataObject::GetOverlapped(lpOverlapped));

BOOL res = FALSE;

HELPER_METHOD_FRAME_BEGIN_RET_1(overlapped); // Eventually calls BEGIN_SO_INTOLERANT_CODE_NOTHROW

// OS doesn't signal handle, so do it here
overlapped->Internal = 0;



res = ThreadpoolMgr::PostQueuedCompletionStatus(lpOverlapped,
BindIoCompletionCallbackStub);
这被称为
ThreadPoolNative::CorPostQueuedCompletionStatus, LPOVERLAPPED lpOverlapped)
ThreadpoolMgr::CallbackForContinueDrainageOfCompletionPortQueue
在一个或多个 IO 完成完成后的某个时间执行 IO 完成回调。由于您自己处理所有事情,因此没有人调用 ThreadpoolMgr::CallbackForContinueDrainageOfCompletionPortQueue 来通知您已完成的 IO 完成发起的读取请求。

关于c# - 为什么我的 IOCompetionCallback 从未在我的 IO 完成端口上执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68649997/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com