Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Синхронизация потоков  (Прочитано 18299 раз)
0 Пользователей и 1 Гость смотрят эту тему.
zss
Участник

ru
Offline Offline

« : 15-07-2004 07:27 » 

Доброго всем дня !

Насколько я помню, процесс, создавая какой-либо объект ядра, создает в своем адресном пространстве таблицу описателей, в которую помещает описатель объекта (HANDLE), его адрес в памяти и флаги. По-сути, HANDLE - это индекс в таблице описателей.

В самой структуре объекта счетчик владельцев = 1. Если какой либо процесс (или поток) получает доступ к данному объекту, то счетчик увеличивается на 1. Для того, чтобы система сама удалила объект ядра - необходимо закрыть все описатели (CloseHandle()). Как только счетчик = 0, система удаляет объект из памяти. Причем закрывая HANDLE происходит только удаление записи в таблице описателей и уменьшение счетчика.

Вроде бы все так.

У меня существует один процесс P1 (user-mode приложение), который создает объект (event), и второй P2 (драйвер) - который получает к нему доступ (тоесть число владельцев = 2). Описатель объекта храниться в глобальной переменной как у Р1 так и у Р2. Далее существует некое множество потоков Рn, которые выполняют код процесса Р2. Причем они синхронизируются с помощью KeWaitForSingleObject.

Теперь вопросы:

1. Получат ли потоки Pn доступ к объекту event используя только KeWaitForSingleObject, ведь адрес event хранится в глобальной переменной P2 (а код выполняется в адресном пространстве этого процесса).

2. Увеличивается ли счетчик, если какой либо поток вызывает KeWaitForSingleObject ?

3. Ведет ли объект event вообще подсчет числа владельцев (к примеру mutex точно ведет)

4. Если ведет, то как освободить event, если я не знаю сколько раз был захвачен этот объект ?

Все вопросы к тому, что event сбрасывается в драйвере, но пользовательское приложение не может его взвести.
Записан
mad
Гость
« Ответ #1 : 15-07-2004 11:41 » 

1. Получат ли потоки Pn доступ к объекту event используя только KeWaitForSingleObject, ведь адрес event хранится в глобальной переменной P2 (а код выполняется в адресном пространстве этого процесса).
Не процесса, а ядра. Да.

2. Увеличивается ли счетчик, если какой либо поток вызывает KeWaitForSingleObject ?
нет

3. Ведет ли объект event вообще подсчет числа владельцев (к примеру mutex точно ведет)
да,конечно, есть поле рефренс каунт.только оно само ничего не бывает.

4. Если ведет, то как освободить event, если я не знаю сколько раз был захвачен этот объект ?
obdereferenceobject
Записан
zss
Участник

ru
Offline Offline

« Ответ #2 : 15-07-2004 12:38 » 

Спасибо - по первым трем вопросам я понял

Цитата

4. Если ведет, то как освободить event, если я не знаю сколько раз был захвачен этот объект ?
obdereferenceobject


Тоесть здесь KeClearEvent не поможет ? А если использовать ObDereferenceObject - то эта функция гарантирует освобождение от всех захватов (которые кстати могут происходить в момент освобождения)?

и еще вопрос
event создается в user-mode приложении. В драйвер я передаю HANDLE, а получаю доступ к объекту

Код:

ObReferenceObjectByHandle)hReadEvent, GENERIC_ALL, NULL, KernelMode, &pReadEvent, NULL:;


Этого достаточно или надо еще что-то (ну к примеру KeInitializeEvent...)

Спасибо
Записан
mad
Гость
« Ответ #3 : 15-07-2004 13:11 » 

Цитата

Тоесть здесь KeClearEvent не поможет ? А если использовать ObDereferenceObject - то эта функция гарантирует освобождение от всех захватов (которые кстати могут происходить в момент освобождения)?

Я под освобождением я имел ввиду дерефренс. Для сброса ивента, нужно keclearevent, Состояние объекта и рефренс каунт - разные поля структуры объекта. Почему они должны быть связаны? Я не понимаю накой тебе рефренс, рефренс с текущим состоянием объекта не связан! Очистишь рефренс и вызовешь keclearevent - получишь BSOD в худшем случае.


Цитата

Этого достаточно или надо еще что-то (ну к примеру KeInitializeEvent...)

достаточно
Записан
zss
Участник

ru
Offline Offline

« Ответ #4 : 15-07-2004 13:20 » 

Спасибо за советы Ага

Но если все так хорошо как я думая, то почему происходит следующее :
когда драйвер сбрасывает event - пользователь начинает читать, а драйвер ждет. Когда пользователь все вычитал из буфера, то он выставляет event, а драйвер все-равно продолжает ждать ?
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #5 : 15-07-2004 13:34 » 

Цитата

Далее существует некое множество потоков Рn, которые выполняют код процесса Р2.


Сильная фраза. Только драйвер- это не процесс. А отсюда возникает вопрос- какой HANDLE ты хранишь в драйвере и как он получен(в контексте какого процесса).
Записан
Anonymous
Гость
« Ответ #6 : 15-07-2004 16:07 » 

когда драйвер <сбрасывает> event - пользователь начинает читать
то он <выставляет> event, а драйвер все-равно продолжает ждать

как ты инициализировал ивент в юзер моде? как авторесет?
Записан
Anonymous
Гость
« Ответ #7 : 15-07-2004 16:08 » 

попробуй авторесет и не используй ресета ивента вручную
Записан
maad
Гость
« Ответ #8 : 15-07-2004 16:09 » 

..
Записан
zss
Участник

ru
Offline Offline

« Ответ #9 : 16-07-2004 05:51 » 

Отвечаю

1.
Цитата
как ты инициализировал ивент в юзер моде? как авторесет?


Так. Причем функция чтения в отдельном потоке
Код:

hReadEvent = CreateEvent)NULL, FALSE, FALSE, NULL:;
if )hReadEvent:|
    hWriteEvent = CreateEvent)NULL, TRUE, TRUE, NULL:;
    if )hWriteEvent:|
        ...
        HANDLE hThread = )HANDLE:_beginthreadex )NULL, 0, ReadMemory, NULL, 0, &ThreadID:;
        ....
    "
"


2.
Цитата

Сильная фраза. Только драйвер- это не процесс. А отсюда возникает вопрос- какой HANDLE ты хранишь в драйвере и как он получен(в контексте какого процесса).


В контексте user-mode (DriverDeviceControl). Я из user-mode приложения передаю HANDLE, а драйвер в контексте user-mode
Код:

ObReferenceObjectByHandle)hReadEvent, GENERIC_ALL, NULL, KernelMode, &pReadEvent, NULL:;
Записан
Anonymous
Гость
« Ответ #10 : 16-07-2004 07:08 » 

попробуй так

hWriteEvent = CreateEvent(NULL, <FALSE>, TRUE, NULL);
Записан
mad
Гость
« Ответ #11 : 16-07-2004 07:10 » 

и убери все ResetEvent
Записан
zss
Участник

ru
Offline Offline

« Ответ #12 : 16-07-2004 07:15 » 

К сожалению мне так нельзя делать  Жаль

Потому, что происходит не одна запись в разделяемый буфер, а к примеру 500 записей. А когда буфер заполнился - тогда разрешение на его чтение.

Если делать оба event с автосбросом, то тогда писать и читать прейдется тольео по одной записи, что увеличивает нагрузку на процессор
Записан
mad
Гость
« Ответ #13 : 16-07-2004 15:20 » 

Хм....странная у тебя организация доступа к буферу....очень уж простая. Мне этого не понять
Записан
zss
Участник

ru
Offline Offline

« Ответ #14 : 17-07-2004 10:39 » 

Цитата: mad
Хм....странная у тебя организация доступа к буферу....очень уж простая. Мне этого не понять


А ты можешь предложить что-то иное ?
Записан
zss
Участник

ru
Offline Offline

« Ответ #15 : 21-07-2004 12:41 » 

Недавно еще раз пролистал Рихтера (прикольные все-таки он дядька Показываю язык   - понятно пишет).
Так вот появилась идея. А если все организовать таким образом:

1. Функция записи построена не на event, а на mutex - для монопольного доступа к буферу (ну и естественно для инкримента счетчика записей использовать interlock - функции).
2. Тем самым запись будет производится монопольно, а HANDLE mutex-а не надо будет передовать из пользовательского приложения.
3. из user-mode приложения передается только event для чтения и записи - а используются они только для синхронизации чтения (тоесть когда буфер заполнился - сигнализируем пользователю о том, что можно читать и ждем конца чтения)

В этом случае вроде не должно быть dedlock-ов
Как Вы думаете - это прокатит, или есть в чем-то ошибка ?
Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 21-07-2004 13:15 » 

zss, дедлок может возникнуть, если есть более одного объекта синхронизации.  Пока только один буфер, то всё будет в порядке.

Если буферов два, скажем B1 и B2, процесс P1 залочил мутекс на B1, процесс P2 залочил мутекс на B2.  Предположим, что для завершения работы процессу P1 нужен доступ к буферу B2, а процессу P2 доступ к буферу B1.  Если процессы будут тупо лочить буферы, то они навечно (до прекращения работы одного из процессов) друг друга будут ждать. Дедлок.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #17 : 22-07-2004 13:39 » 

Цитата

1. Функция записи построена не на event, а на mutex - для монопольного доступа к буферу (ну и естественно для инкримента счетчика записей использовать interlock - функции).
2. Тем самым запись будет производится монопольно, а HANDLE mutex-а не надо будет передовать из пользовательского приложения.
3. из user-mode приложения передается только event для чтения и записи - а используются они только для синхронизации чтения (тоесть когда буфер заполнился - сигнализируем пользователю о том, что можно читать и ждем конца чтения)


На первый взгляд это вобще никакая не синхронизация. Вот заполнился буфер и ты через event сказал читать, а в этот момент кто-то хватает мютекс и начинает писать, а ты читаешь то что записали. Фигняс получается.
Записан
zss
Участник

ru
Offline Offline

« Ответ #18 : 23-07-2004 05:21 » 

Цитата
На первый взгляд это вобще никакая не синхронизация. Вот заполнился буфер и ты через event сказал читать, а в этот момент кто-то хватает мютекс и начинает писать, а ты читаешь то что записали. Фигняс получается.


Как ни странно, но этот код заработал !!!

Если буфер заполнился, то я говорю читать и жду конца чтения. Если же кто-то пытается в этот момент захватить mutex, то он будет ждать. Как пишет Рихтер - mutex используется для монопольного доступа к разделяемым ресурсам. Как только я KeReleaseMutex, то система проверяет какой из потоков ожидает mutex и передает его во владение только одному потоку (причем Microsoft гарантирует что алгоритм выбора честный, тоесть не зависит от привелегий потока)
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #19 : 06-08-2004 11:19 » new

Цитата

Как ни странно, но этот код заработал !!!


Если код типа

<Захватил ресурс>
Работа с буфером
<Освободил ресурс>

Работать он естественно будет если все потоки так делают, но то что ты написал этому не соотвествует, у тебя зачем то два объекта- event и mutex.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines