gpt4 book ai didi

c - 异步 ReadDirectoryChangesW - GetQueuedCompletionStatus 总是超时

转载 作者:太空狗 更新时间:2023-10-29 16:49:25 31 4
gpt4 key购买 nike

正如它听起来的那样,我正在尝试异步 ReadDirectoryChangesW 和 IO 完成,但它不起作用,具体来说,GetLastError 重复返回 258 (GetQueuedCompletionStatus 超时)。

我有结构:

typedef struct dirinfo_struct
{
HANDLE hDirFH; // directory handle
OVERLAPPED Overlapped; // overlapped storage
int len_buffer; // buffer length
wchar_t* buffer; // buffer itself
wchar_t* directory_name; // target name
} dirinfo_t;

typedef struct dirmon_struct
{
HANDLE hDirOPPort; // handle to the IO port.
dirinfo_t* dirinfo; // pointer to the struct above.
} dirmon_t;

用于存储相关信息。这是初始化的:

dirinfo_t* t = malloc(1*sizeof(dirinfo_t));
dirmon_t* d = malloc(1*sizeof(dirmon_t));
dirinfo_init(t); // does t->buffer = malloc(8192*sizeof(wchar_t));

然后我创建我的目录句柄和 com 端口:

t->hDirFH = CreateFile(L"C:\\test",
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
d->dirinfo = t;
d->hDirOPPort = CreateIoCompletionPort(d->dirinfo->hDirFH,
NULL,
(ULONG_PTR)(d->dirinfo),
1);

然后我通过 d 将此信息传递给一个新线程。现在在我所说的新线程上:

bResultQ = GetQueuedCompletionStatus(d->hDirOPPort, lpBytes, 
(ULONG_PTR*)d->dirinfo,
lpOverlapped, 1000);

if ( bResultQ )
{
bResultR = ReadDirectoryChangesW(d->dirinfo->hDirFH,
(void*)d->dirinfo->buffer,
8192, TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY,
lpReadDirBytes,
&d->dirinfo->Overlapped,
NULL );
}
else
{
printf("GetQueuedCompletionStatus(): Failed, ");
errorcode = GetLastError();
printf("Error Code %d\n", errorcode);
Sleep(500);
}

所以我将其设置为关闭运行,并且由于目录没有更改,我很高兴地得到了超时(258 个错误),这是我应该做的。但是,即使我更改了目录,我仍然会收到错误消息;换句话说,这些更改没有被拾取。这让我相信我的设置不正确。

有什么想法吗?

注意事项:

  • 具有讽刺意味的是,这最终将通过 pywin32 转换为 Python。但是,在我理解这在 C 中应该如何工作之前,我不会去那里。
  • 同步 ReadDirectoryChangesW 不是一个选项。如果没有事件被激发,我需要这个线程超时,以便它可以检查它是否应该仍在运行。
  • 我专门用 C 编写,而不是 C++。
  • FindFirstChangeNotification 等也不是一个选项 - 我不想不断地比较目录列表来找出发生了什么变化。

其他说明:

  • 目录存在,句柄不为空。 comport 句柄也是如此。
  • 一切都被传递给线程

我看过CDirectoryChangeWatcher来自代码项目,但使用 C++ 和更多线程,我看不出我在做什么不同。如果我遗漏了什么,请随时指出!

输出,如果有帮助的话,基本上是重复的,不管我改变多少目录有问题。

GetQueuedCompletionStatus(): Failed, Error Code 258

最佳答案

我意识到发布代码墙通常被认为是可怕的,但我是这样工作的:

新结构:

BOOL runthread;

typedef struct overlapped_struct
{
OVERLAPPED overlapped;
wchar_t* buffer;
} overlapped_t;

typedef struct dirinfo_struct
{

HANDLE hDirOPPort;
HANDLE hDirFH;
overlapped_t* o;
int len_buffer;
wchar_t* buffer;
wchar_t* directory_name;
ULONG_PTR CompletionKey;
} dirinfo_t;

int somekey = 1;

分配方式:

void dirinfo_init(dirinfo_t* t)
{
t->buffer = malloc(16777216*sizeof(wchar_t));
t->len_buffer = 16777216;
t->o = calloc(1, sizeof(overlapped_t));
t->o->buffer = calloc(16777216, sizeof(wchar_t));
memset(t->o->buffer, 0, 16777216);
memset(t->o, 0, sizeof(OVERLAPPED));
}

void dirinfo_free(dirinfo_t* t)
{
free(t->buffer);
free(t->o->buffer);
free(t->o);
free(t);
}

main() 中的重要内容是这样做的:

dirinfo_t* d = malloc(1*sizeof(dirinfo_t));
d->CompletionKey = (ULONG_PTR)&somekey;
dirinfo_init(d);

/* set up */
runthread = TRUE;
d->hDirFH = CreateFile(L"C:\\hydratest",
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);

d->hDirOPPort = CreateIoCompletionPort(d->hDirFH, NULL,
(ULONG_PTR)d->CompletionKey, 1);

最后是我的等待线程。关键在于:我没有传入重叠结构。我传入的结构包含一个 OVERLAPPED 加上相当数量的基于 wchar_t 的存储。由于我不完全理解的原因,这有效。 编辑参见this answer .我相信这里的数据区域充当重叠缓冲区。

DWORD WINAPI WaitingThread(void* args)
{
DWORD errorcode = 0; // an error code
BOOL bResultQ = FALSE; // obvios=us
BOOL bResultR = FALSE;
DWORD NumBytes = 0;
FILE_NOTIFY_INFORMATION* pInfo = NULL; // the data incoming is a pointer
// to this struct.
int i = 0;
dirinfo_t* d = (dirinfo_t*) args; // rescue struct from thread arg.

然后我们进入主线程本身。反复试验表明您应该同时调用 ReadDirectoryW 和 GetQueueCompletionStatus。 我认为这意味着我们不应该接触来自 ReadDirectoryChangeW 的缓冲区**除非*我们被告知我们可以通过 GetQueue。然而,欢迎对该假设进行更正。

    while ( runthread )
{
bResultR = ReadDirectoryChangesW(d->hDirFH, (void*)d->buffer,
16777216, TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY,
NULL,
&d->o->overlapped,
NULL );
bResultQ = GetQueuedCompletionStatus(d->hDirOPPort,
&NumBytes, &(d->CompletionKey),
(LPOVERLAPPED*)(d->o), 1000);

所以,现在我们已经调用了这些函数,我们然后测试它们是否都返回 true。 丑陋的大警告 如果您的参数设置正确,bResultR 总是返回 true,或者在我看来是这样。 bResultQ 然而,取决于端口上是否有新数据。

        if ( bResultQ && bResultR )
{

所以在这里我们从 ReadDirectoryChangesW 转换缓冲区并从结构访问信息。

            wprintf(L"\n");
pInfo = (FILE_NOTIFY_INFORMATION*) d->buffer;
wprintf(L"File %s", pInfo->FileName);
wprintf(L" changes %d\n", pInfo->Action);
memset(d->buffer, 0, 16777216);
}

否则,和thanks to Tony for this ,您可以安全地忽略 WAIT_TIMEOUT 错误,但任何其他错误都可能意味着您有麻烦了。

        else
{
errorcode = GetLastError();

if ( errorcode == WAIT_TIMEOUT )
{
printf("GetQueuedCompletionStatus(): Timeout\n");
}
else
{
printf("GetQueuedCompletionStatus(): Failed\n");
printf("Error Code %d\n", errorcode);
}
Sleep(500);
}
}

return 0;
}

我认为这是一个可行的示例。

一些注意事项:

  • 我已将缓冲区大小设置得很大。我注意到复制了 100 个左右的文件,缓冲区用完了设置为 8192 的空间,并且遗漏了一两个项目,到处都是。所以我不认为这会总是解决所有问题。我的解决方案是说每 100 个事件,如果使用此方法,请验证文件树是否如您所想。然而,一个更好的解决方案是不断枚举潜在的大树。

关于c - 异步 ReadDirectoryChangesW - GetQueuedCompletionStatus 总是超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6150984/

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