正如听起来的那样,我尝试使用IO完成的异步ReadDirectoryChangesW,但它不起作用,特别是,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个错误),因为我应该,因为目录没有改变。然而,即使我改变了目录,我仍然会收到错误消息;换句话说,这些修改不会被发现。这让我相信我把这个设置错了。
有什么想法吗?
注意事项:
ReadDirectoryChangesW不是一个选项。如果没有事件被触发,我需要这个线程来超时,这样它就可以检查它是否还在运行。FindFirstChangeNotification等也不是一个选项--我不想不断地比较目录列表,找出已经改变了什么。其他说明:
我看了一下代码项目中的CDirectoryChangeWatcher,但是除了使用C++和更多线程之外,我看不出我在做什么不同。不过,如果我漏掉了什么,可以随时指出!
输出,如果有帮助的话,基本上是重复的,不管我修改了多少目录。
GetQueuedCompletionStatus(): Failed, Error Code 258发布于 2011-05-27 22:54:18
我意识到,张贴代码墙通常被认为是可怕的,但下面是我如何做到这一点的:
新结构:
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的存储的结构。由于我不完全理解的原因,这是可行的。编辑见这个答案。我认为这里的数据区域充当重叠缓冲区。
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。如果您设置了正确的参数,那么大警告总是返回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);
}否则,和感谢托尼的这一切一样,您可以安全地忽略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;
}我认为这是一个有用的例子。
一些注意事项:
8192的空间,遗漏了一两个项目。所以我不认为这会带来所有的东西。我的解决方案是每100个事件说一次,验证如果使用这种方法,文件树就是您所认为的那样。一个无限好的解决方案,但是,不断枚举潜在的大树。发布于 2011-05-27 19:37:36
注意:要正确捕获来自GetQueuedCompletionStatus的错误,因为很难确定此函数是否实际返回,应按以下方式执行:
例子:
DWORD dwNumBytes;
ULONG_PTR CompletionKey;
OVERLAPPED* pOverlapped;
//hIOCP is initialized somewhere else in the program
BOOL bOK = GetQueuedCompletionStatus(hIOCP, &dwNumBytes, &CompletionKey, &pOverlapped, 1000);
DWORD dwError = GetLastError();
if(bOK)
{
// Process a successfully completed I/O event.
}
else
{
if (pOverlapped != NULL)
{
// Process a failed completed I/O request
//dwError contains the reason for failure
}
else {
if (dwError == WAIT_TIMEOUT)
{
//Time-out while waiting for completed I/O entry.
}
else {
//Bad call to GetQueuedCompletionStatus
//dwError contains the reason for the bad call.
}
}示例摘自本书(Windows通过C/C++),请尝试在代码中实现此错误处理。
此外,“.调用GetQueuedCompletionStatus的线程是以最后进入先出(LIFO)的方式唤醒的。”
重叠结构: 执行异步设备I/O时,必须通过pOverlapped参数将地址传递给初始化的pOverlapped重叠pOverlapped结构。此上下文中的“重叠”一词意味着执行I/O请求的时间与线程执行其他任务的时间重叠。
它讨论的是调用ReadFile或WriteFile时的参数,这需要初始化该结构。
它看起来如下:
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;注意到:您正在传递指向指向CreateIoCompletionPort函数的dwCompletionKey参数的结构的指针。在我所看到的引用中,它们只是传递一个常量(#define CK_FILE 1)给它。它确实说你可以通过任何你喜欢的,因为操作系统不关心。只是想指出这一点。
https://stackoverflow.com/questions/6150984
复制相似问题