Доброго времени суток! У У.Они , когда речь идет о спин блокировках, есть такое уточнение “an atomic operation that tests and then sets a memory variable in such a way that no other CPU can access the variable until the operation completes”. Воот.. KeAcquireSpinLock(…) на асме (машины с дебагером нету под рукой, и посмотреть смогу не скоро,но видимо это так) представляет сабой некоторый набор инстукций, я не уверен в порядке следования, но условно оное действо, как я полагаю,включает в себя некоторые инструкции проверки, инуструкции установки, прочую херь(уж я не знаю точно именно irql там повышается, мож что путаю). Может я уже херь сморозил, но я приведу собственно сам вопрос, чтобы добрые люди помогли прояснить неразбериху. Рассмотрим ситуацию, да потока (П)оток1 и (П)оток2. Значит теоретически может возникнуть такая ситуация //Выполняется код П1 на CPU1 … какие-то телодвижения … KeAquireSpinLock()//теперь конкретно в этом вызове Выполняются инструкции проверки, все хорошо, доступ разрешен //Выполняется код П2 на CPU2 KeAquireSpinLock(тот ж объект KSPIN_LOCK) И он тоже успешно проходит проверку, так как поток 1 "не успел"(?) еще добраться до инструкций «взводящих» спинблокировку. //а здесь тем временем в П1 Выполняются инструкции устанавливающие спинблокировку. Таким образом при НЕКОТОРОМ стечении обстоятельств два потока усешно чекнуть спин блокировку. Допустим вариант на системе с 1 процом.Да я читал, что в однопроцессорной системе гемороя меньше и при захвате спинблока поток просто повышает IRQL до DISPATCH_LEVEL. но в любом случае будут инструкции проверки и установки.И квант П1 может кончится ровно после инструкций проверки, тогда П2 теоретически может в своем коде чекнуть спинблок, а далее уже хоть трава не расти...О.о Чую, что собака зарыта в atomic operation, но что именно это означает не пойму, точнее не пойму как оное может быть реализовано.Как эта она не может быть вытеснена? Собственно вопрос можно интерполировать и на объекты синхронизации типа событий мютексов и тд. Как реализуется (и реализуется ли вообще) защита от вытеснения на каком то шаге KeWaitForSingleObject KeWaitForMultipleObject Ведь в любом случает есть(?) инструкции проверки а потом уже захвата объекта, и почему между ними то как раз не может вклинится другой поток и опять запросить проверку? Заранее благодарен!
atomic operation - операция выполняющаяся атомарно. Фактически перед такой инструкцией подается префикс LOCK, который блокирует шину адресса. Таким образом можно проверять значение, изменять и ... т.д. некоторые переменные атомарно.
Блин говорили мне читай Зубкова Спасибо за наводку, покопал в сторону lock и тд.Ну теперь вырисовывается.
Это примитива операционки - семафоры, spinlocks, mutexes, и т.д. Про атомарные инструкции тебе уже ответили, а эти вещи - чисто теоретическая абстракция. Напремер mutex (win32 critical section) - всё упирается в системный вызов который блокирует поток. То есть, примитива даёт эксклюзивный доступ для обычного потока.
solarian , ты прости, но твой коментарий, вообще не ответ ни разу. Я знаю, что такое примитивы синхронизации и как ими пользоваться.точнее думал так Вопрос был в том как конкретно может быть организована защита от вытеснения между инструкциями проверки и установки. Я тут полистал зубкова и мануал интела и всетаки... lock - это префикс для блокировки шины на время выполнения микрокоманд в рамках одной инструкции те типа: lock xadd lock xchg но между ними все равно код может быть вытеснен! Те в рамках П1 между проверкой состояния спинлока и его установкой код в П2 может также совершить успешную проверку этого самого спинлока.И далее оба потока будут пытаться установить энтот спинлок, соответственно бсод. вот небольшая вырезка из Oney в коментариях для ExInterlockedAddLargeStatistic.Да для каждой инструкции lock работает, но между ними... А именно, lock конечно спасает в рамках одной инструкции, но между ними может быть чито угодно. Все таки не понял я этот момент.Вразумите пожалуйста Боюсь теперь объектов синхронизации, придется переходить под дос Я не нашел пока нигде толкового пояснения этой ситуации.
В отрывке про 64-битную переменную. Чтобы с ней работать, надо установить спинлок сначала. Идея в том, что инструкцию xchg eax,[spinlock] процессоры выполнят один за другим, соответственно, 0 из spinlock в eax получит только один из них, а второй уже получит 1, поймёт, что спинлок занят и пойдёт крутиться (spin – отсюда и название) в wait, дожидаясь следующего благоприятного случая (но и когда он его дождётся, нет гарантии, что у него получится захватить ресурс). Код (Text): spinlock dd 0 acquire: xor eax,eax inc eax ; EAX = 1. xchg eax,[spinlock] ; LOCK неявный тут. test eax,eax ; Проверяем, что было в spinlock до нас (было ли свободно)? jnz .wait ; Было 1 (занято)? Тогда ждём. work: ; делаешь своё чёрное дело с данными xor eax,eax mov [spinlock],eax ; Освобождаем. jmp done wait: cmp [spinlock],0 ; Занято? jnz wait ; Ждём, если занято. jmp acquire ; Не занято. Попробуем завладеть. done:
xchg....xchg...как все просто! Благодарствую!теперь все точно clear UPDT: если кому вдруг будет интересно, то вот дернул из hal.dll: Код (Text): KfAcquireSpinLock: ;судя по мануалу ia32 fffe0080 энто у нас "the address of TPR register of Local APIC" ;а следовательно со старта эта функция поднимает уровень irql, видимо до ;уровня DISPATCH_LEVEL, а потом уже делаются все сеты и тесты...от так вот :) mov edx,[FFFE0080h] mov dword ptr [FFFE0080h],00000041h shr edx,04h movzx eax,[edx-7FFE2DE8h] L1_8001284A: lock bts dword ptr [ecx],00h ;чутка подредактировал jc L1_80012854 retn L2_80012854: test dword ptr [ecx],00000001h jz L2_8001284A pause jmp L80012854 retn