使用线程时Windows WriteFile问题

Windows WriteFile problem when using threads

本文关键字:WriteFile 问题 Windows 线程      更新时间:2023-10-16

我的公司正在开发一种需要与软件通信的硬件。为此,我们制作了一个驱动程序,可以对硬件进行读写。要访问驱动程序,我们使用命令:

HANDLE device = CreateFile(DEVICE_NAME,
                                GENERIC_READ | GENERIC_WRITE,
                                0x00000007,
                                &sec,
                                OPEN_EXISTING,
                                0,
                                NULL);

读写使用以下函数完成:

WriteFile(device,&package,package.datasize,&bytesWritten,NULL);

ReadFile(device,returndata,returndatasize,&bytesRead,NULL);

最后是CloseHandle(device),用于关闭文件。

这在从主线程调用函数的情况下工作得很好。如果从其他线程调用它们,则在尝试写入多个元素时得到错误998 (no_access)。使用

创建线程
CreateThread(NULL, 0, thread_func, NULL, 0, &thread_id);
我已经没有主意了,你有什么建议吗?

编辑:当运行以下序列时:

Main_thread:
CreateFile
Write
Close
CreateThread
WaitForThread
Thread_B:
CreateFile
Write
Close

Main_Thread成功,Thread_B失败。但是,当写入小数据集时,这种方法可以很好地工作。这可能是因为Thread_B没有继承所有的Main_Thread的访问权限吗?

edit2:这里有很多好的想法,非常感谢!在对这个问题进行了一些研究之后,情况似乎如下:

api包含一个Queue-thread,处理所有进出设备的包。这个线程处理指向包对象的指针。当指针到达队列的前面时,调用"send_and_get"函数。如果包中的数组是在调用"send_and_get"函数的同一个线程中分配的,则一切正常。如果数组是在其他线程中分配的,则发送失败。

根据winerror, Win32错误998是以下本机状态值之一(由O/S或驱动程序返回):

   998 ERROR_NOACCESS <--> 0x80000002 STATUS_DATATYPE_MISALIGNMENT
   998 ERROR_NOACCESS <--> 0xc0000005 STATUS_ACCESS_VIOLATION
   998 ERROR_NOACCESS <--> 0xc00002c5 STATUS_DATATYPE_MISALIGNMENT_ERROR

访问冲突可能是一个可能的候选者,基于您所说的"当试图写入多个元素时"。您确定要发送的缓冲区足够大吗?

对齐错误是相当奇特的,但如果设备有一些对齐要求,并且开发人员选择使用这些特定的错误,则可能相关。

斯科特

听起来还是像并发访问。写此设备的单独线程需要使用互斥锁或类似的方法来正确保护对文件的访问。要么在主线程中打开句柄并保持打开状态,要么保护每个线程中可能发生的整个open -> Write -> Close序列(使用互斥锁)。

作为调试措施,因为它是您自己的驱动程序,您可以让驱动程序记录它正在接收的请求,例如,记录到事件日志中。设置两个相同的测试运行,除了一个在主线程中运行所有代码,另一个在第二个线程中运行所有代码。比较结果可以让你更好地了解发生了什么。

让您的驱动程序报告它返回到操作系统的任何错误代码也是一个好主意。

您应该检查的第一件事是,在请求到达您的驱动程序之前,您的驱动程序或内核模式I/O管理器(负责启动IRP并调用您的驱动程序)是否报告了错误(998)。您应该能够发现这一点,因为这是您的驱动程序。只需记录对驱动程序的调度例程的调用,它返回什么,它做了什么(它是否调用其他驱动程序或调用带有错误代码的IoCompleteRequest等),事情就会变得清晰起来。

从你描述的场景来看,似乎最有可能的错误是由你的驱动程序引起的。例如,您的驱动程序可能在响应CreateFile(这是驱动程序的IRP_MJ_CREATE)时分配一些全局状态结构,并在文件关闭时清除它。如果同时打开两个文件,然后关闭一个文件,而另一个文件仍然接收I/O请求,那么这样的驱动程序将无法正常工作。