Проблема Windows WriteFile при использовании потоков - PullRequest
2 голосов
/ 01 сентября 2011

Моя компания разрабатывает оборудование, которое должно взаимодействовать с программным обеспечением.Для этого мы создали драйвер, который позволяет записывать и читать с аппаратного обеспечения.Чтобы получить доступ к драйверу, мы используем команду:

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 (устройство), чтобы закрыть файл.

Это прекрасно работает в случае, когда функции вызываются из основного потока.Если они вызываются из какого-то другого потока, мы получаем ошибку 998 (no_acccess) при попытке записать более пары элементов.Потоки созданы с использованием

CreateThread(NULL, 0, thread_func, NULL, 0, &thread_id);

У меня заканчиваются идеи здесь, какие-либо предложения?

edit: при выполнении следующей последовательности:

Main_thread:
CreateFile
Write
Close
CreateThread
WaitForThread

Thread_B:
CreateFile
Write
Close

Main_Thread успешно выполняется, а Thread_B - нет.Однако при записи небольших наборов данных это работает нормально.Может ли это быть потому, что Thread_B не наследует все привилегии доступа Main_Thread?

edit2: здесь много хороших размышлений, высоко ценится!После некоторой работы над этой проблемой, похоже, имеет место следующее:

API содержит поток очереди, обрабатывающий все пакеты, поступающие на устройство и с него.Этот поток обрабатывает указатели на объекты пакета.Когда указатель достигает начала очереди, вызывается функция send_and_get.Если массивы в пакете расположены в том же потоке, который вызывает функцию send_and_get, все работает нормально.Если массивы размещены в каком-то другом потоке, отправка не удалась.Но как это исправить, я не знаю.

Ответы [ 4 ]

3 голосов
/ 01 сентября 2011

Согласно winerror, ошибка 998 Win32 является одним из следующих собственных значений состояния (которые будут возвращены O / S или драйвером):

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

Нарушение доступа может быть вероятным основанным кандидатомна вас говорят "при попытке написать больше, чем пару элементов".Вы уверены, что буфер, который вы отправляете, достаточно велик?

Ошибки выравнивания довольно экзотичны, но могут иметь значение, если к устройству предъявляются некоторые требования к выравниванию, и разработчик решил использовать эти конкретные ошибки.

-скотт

2 голосов
/ 01 сентября 2011

По-прежнему звучит для меня как одновременный доступ. Ваши отдельные потоки, пишущие на это устройство, должны будут надлежащим образом защитить доступ к файлу с помощью мьютекса или аналогичного. Либо откройте дескриптор в главном потоке и оставьте его открытым, либо защитите всю последовательность Open -> Write -> Close, которая может происходить в каждом потоке (с мьютексом).

1 голос
/ 04 сентября 2011

Первое, что вы должны проверить, - это ошибка (998), сообщенная вашим драйвером или менеджером ввода-вывода в режиме ядра (который отвечает за запуск IRP и вызов вашего драйвера) даже до того, как запрос достигнет вашего драйвера , Вы должны быть в состоянии обнаружить это, поскольку это ваш драйвер. Просто зарегистрируйте вызовы в диспетчерской программе драйвера, что она возвращает, что она делает (она вызывает другие драйверы или вызывает IoCompleteRequest с кодом ошибки или т. Д.), И все должно стать понятным.

Из описанного вами сценария кажется, что, скорее всего, ошибка вызвана вашим драйвером. Например, ваш драйвер может выделить некоторую глобальную структуру состояний в ответ на CreateFile (то есть драйвер * IRP_MJ_CREATE) и очистить ее, когда файл будет закрыт. Такой драйвер не будет работать правильно, если одновременно открыты два файла, один из которых закрыт, а второй все еще получает запросы ввода-вывода.

1 голос
/ 04 сентября 2011

В качестве меры отладки, поскольку это ваш собственный драйвер, вы можете заставить драйвер записывать полученные запросы, например, в журнал событий.Установите два одинаковых прогона теста, за исключением того, что один запускает весь код в главном потоке, а другой - весь код во втором потоке.Сравнение результатов должно помочь вам лучше понять, что происходит.

Также было бы неплохо заставить ваш драйвер сообщать о любых кодах ошибок, которые он возвращает операционной системе.

...