Как безопасно разделить переменную с потоком, который находится в другом модуле компиляции? - PullRequest
0 голосов
/ 21 июля 2011

В структуре моей программы я разделил «откуда она вызывается» и «что делается» на отдельные исходные файлы. На практике это позволяет мне скомпилировать программу как автономную или включить ее в DLL. Приведенный ниже код - это не реальный код, а упрощенный пример, который подтверждает то же самое.

Здесь есть 3 взаимодействующих компонента: программа режима ядра, которая загружает мою DLL, DLL и ее исходные файлы, и служебная программа с ее источником, которая поддерживается отдельно.

В форме DLL программа загружается как поток. Согласно документации поставщика приложений режима ядра, я теряю возможность вызывать функции Win32 API после инициализации программы ядра, поэтому я загружаю поток как активный поток (в отличие от использования CREATE_SUSPENDED, поскольку я не могу его разбудить).

У меня есть монитор переменной флага, чтобы он знал, когда делать что-то полезное с помощью не элегантного, но функционального:

while ( pauseThreadFlag ) Sleep(1000);

Допускается задержка до 1 секунды (общий процесс занимает много времени и редко вызывается) и, похоже, не влияет на систему.

В исходном файле потока я объявляю переменную как

volatile bool pauseThreadFlag = true;

В объявленном мной исходном файле DLL

extern volatile bool pauseThreadFlag;

и когда я буду готов выполнить поток, в DLL я установлю

pauseThreadFlag = false;

У меня были некоторые трудности с объявлением объектов std :: string как volatile, поэтому вместо этого я объявил свои параметры как глобальные переменные в исходном файле потока и установил установщики вызовов DLL, которые находятся в источнике потока. Эти строки были бы параметрами, если бы я мог создать поток по желанию.

(Отсутствует все это - блокировка переменной для безопасности потока, что является моим следующим "делом")

Это кажется мне плохим дизайном ... он функциональный, но запутанный. Учитывая ограничения, которые я упомянул, есть ли лучший способ сделать это?

Я думал, что возможной ревизией будет использование переменной LPVOID lpParams, заданной при создании потока, для хранения указателей на строковые объекты, даже если строки будут пустыми при создании потока, и доступ к ним непосредственно из потока таким образом стирать объявления, сеттеры и т. д. в поточной программе вообще? Если это работает, тогда на флаг паузы можно было бы также ссылаться, а объявления extern исключать (но я думаю, что он все еще должен быть объявлен как volatile для намека на оптимизатор).

Если это имеет какое-либо значение, среда Visual Studio 2010, C ++, целевая платформа Win32 (XP).

Спасибо!

Ответы [ 2 ]

1 голос
/ 21 июля 2011

Если все компоненты работают в режиме ядра, вам нужно взглянуть на KeInitializeEvent , KeSetEvent , KeResetEvent и KeWaitForSingleObject, Все они работают аналогично своим эквивалентам в пользовательском режиме.

0 голосов
/ 26 июля 2011

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

Использование указателя void cast для этого объекта прошло корректно, и он кажется достаточно стабильным.

...