реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Атомарность операций
sysel
сообщение Oct 2 2009, 07:33
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 3-07-07
Пользователь №: 28 852



Здравствуйте!

Прошу прощения за оффтоп(хотя ОС Windows CE), но проблема такова:

Пишу многопоточную программу под х86 процессор (защищенный режим) на С++.
Есть глобальная переменная (назовём её Count) для взаимодействия двух потоков. (в обоих потоках присутствуют операции чтение, запись и чтение-модификация-запись (Count=Count+A)).
По логике программы операции чтение и запись не могут привести к нарушению работы, а вот чтение-модификация-запись - может.

Возникла идея реализовать операцию Count=Count+A в виде ассемблерной вставки, где операция выполняется инструкцией Add:
__asm{
push eax
mov eax,A
add Count,eax
pop eax
};
, т.к. код, генерируемый компилятором по умолчанию сводился к:
mov eax,Count
mov ebx,A
add eax,ebx ; опасная строка 1
mov Count,eax ; опасная строка 2

Все эти заморочки вызваны тем, что в любом месте моя программа может быть прервана планировщиком ОС. Т.е. если планировщик вклиниться между опасными командами 1 и 2, запустит на выполнение второй поток, который выполнит опасные команды 1 и 2, и опять запустит на выполнение первый поток, который выполнит опасную команду 2, возникнет ситуация "пепец".

Теперь внимание вопрос: если операция Count=Count+A в ассемблерном коде представлена одной процессорной командой Add, гарантирует ли это отсутствие ситуации "пепец" ?

Иными словами, можно ли ассемблерную инструкцию считать атомарной (выполняемой как единое целое) ?

Иными словами: планировщик современных ОС вклинивается между инструкциями x86 или между инструкциями внутреннего RISC-ядра процессора?

На всякий случай добавлю: пользоваться объектами синхронизации ОС (критические секции, Interlocked...) не вышло - очень замедляет работу моего RealTime приложения. Приложение запущено в пользовательском режиме (кольцо 3), cli и sti не советовать.

На всякий случай доп. информация (скорее всего не существенно):
Среда: Visual Studio 2005
ОС(целевая): Windows CE 6.0 R2
Процессор(целевой): AMD Geode LX800 (x86(набор инструкций P5), FPU, MMX, 3DNow!)
Go to the top of the page
 
+Quote Post
KolyanV
сообщение Oct 4 2009, 06:43
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 91
Регистрация: 1-06-05
Пользователь №: 5 621



Команды процессора с точки зрения прерываний - атомарны. Т.е начатая команда обязательно будет выполнена до конца. Правда с учетом конвеерной обработки, не все так гладко. Возможно, завершение выполнения команды будет происходить тогда, когда процессор начнет вход в прерывание. Но, я думаю, это не должно волновать, так как завершение будет занимать доли/единицы тактов.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Oct 4 2009, 07:14
Сообщение #3


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Если ваш код работает в защищенном режиме, то отчего бы не использовать команды запрета и разрешения прерываний? Вот так:

__asm{
push eax
cli
mov eax,A
add Count,eax
sti
pop eax
};

Ведь любой планировщик получает свою "жизненную силу" от прерывания, а раз программу в этом месте нельзя прервать, то никакой планировщик туда не вклинится.
Go to the top of the page
 
+Quote Post
readt
сообщение Oct 4 2009, 13:43
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 44
Регистрация: 23-04-05
Из: Киев
Пользователь №: 4 436



Цитата(sysel @ Oct 2 2009, 10:33) *
Все эти заморочки вызваны тем, что в любом месте моя программа может быть прервана планировщиком ОС. Т.е. если планировщик вклиниться между опасными командами 1 и 2, запустит на выполнение второй поток, который выполнит опасные команды 1 и 2, и опять запустит на выполнение первый поток, который выполнит опасную команду 2, возникнет ситуация "пепец".

Копать нужно в сторону примитивов взаимоисключений.
Описанные проблемы с разделением ресурса несколькими потоками не новы. Вон у классика Дейтела описано несколько алгоритмов.
Под win я бы использовал объекты диспетчеризации ядра (семафоры, мьютексы и проч.). А для защищенного режима попробуйте команду BTS - Bit Test and Set (386+), вот она и является атомарной.

Правильному планировщику должно быть по боку, когда он забирает процессор у потока. Другими словами: отработал квант времени - вон с пляжа.
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Oct 5 2009, 07:20
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(KolyanV @ Oct 4 2009, 09:43) *
Команды процессора с точки зрения прерываний - атомарны. Т.е начатая команда обязательно будет выполнена до конца. Правда с учетом конвеерной обработки, не все так гладко. Возможно, завершение выполнения команды будет происходить тогда, когда процессор начнет вход в прерывание. Но, я думаю, это не должно волновать, так как завершение будет занимать доли/единицы тактов.


В свое время на BlackFin 537 столкнулся с следующей проблемой:

Код
* * * *
volatile int* piReg_;
* * * *
*piReg_ = /* доступ к внешней памяти */

* * *


Так вот: если во время доступа к внешней памяти происходило прерывание, то вместо одного чтения из памяти, иногда получалось 2. К сожалению в причинах не разобрался - просто на время доступа стал отключать прерывания.
Go to the top of the page
 
+Quote Post
KolyanV
сообщение Oct 6 2009, 20:24
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 91
Регистрация: 1-06-05
Пользователь №: 5 621



Цитата(Dima_G @ Oct 5 2009, 10:20) *
В свое время на BlackFin 537 столкнулся с следующей проблемой:
....
Так вот: если во время доступа к внешней памяти происходило прерывание, то вместо одного чтения из памяти, иногда получалось 2. К сожалению в причинах не разобрался - просто на время доступа стал отключать прерывания.

Ничего не скажу по архитектуре блекфина, но приведенный Вами фрагмент мало о чем говорит. Насколько атомарна выполняемая там операция зависит от того, как компилятор его переведет в машиный код. В случае, приведенном топикстартером модификация ячейки памяти выполняется одной командой (add Count,eax) и поэтому она атомарна (во всяком случае в архитектуре x86).

2 xenia: Никаких cli / sci в коде прикладных программ под ОС высокого уровня Windows/Linux быть не может, и это правильно - времена ДОСов прошли.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Oct 6 2009, 22:08
Сообщение #7


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(KolyanV @ Oct 7 2009, 00:24) *
2 xenia: Никаких cli / sci в коде прикладных программ под ОС высокого уровня Windows/Linux быть не может, и это правильно - времена ДОСов прошли.


Не скажите smile.gif. Вы лично пробовали CLI/STI под WinXP или Vista? Да, это привилегированные команды, которые процессор выполняет только в ядре (0-ом кольце защиты), а в приложении они вызывают "исключение", т.е. прерывание по случаю попытки нарушения защиты. Абортируют ли эти команды приложение? А вот и нет! Исключение и в самом деле происходит, однако супервизор решает, что наружение можно простить smile.gif. Т.е. проверив инструкцию, вызвавшую прерывание (это делается легко, т.к. когда происходит прерывание или исключение, ее адрес лежит на стеке), адрес возврата будет увеличен на единичку, благодаря чему управление вернется на инструкцию, следующую за CLI/STI. В результате выполнение приложения продолжится, как будто этих инструкций не было.

Однако то, что я описала - это только механизм "прощения" такого нарушения, а в реальности супервизор может перед "прощением" повысить приоритет потоку, вызвавшему такое исключение, если нарушившая порядок инструкция была CLI. Или вернуть потоку нормальный приоритет, если это была инструкция STI.

Как видите, под управлением современных ОС высокого уровня, примитивы CLI/STI тоже могут работать, только не напрямую, а опосредованно. И это, между прочим, решает массу проблем! Например, аппаратные прерывания от таймера, мыши, DMA и прочего будет продолжать работать, а процесс вытеснения потоков и задач может быть временно приостановлен. Хотя он будет все равно запущен, если STI долго не придет.

Другое дело, что опираться на подобные механизмы можно только тогда, когда в точности знаешь реакцию данной ОС на CLI/STI.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Oct 7 2009, 05:52
Сообщение #8


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Xenia @ Oct 7 2009, 01:08) *
Другое дело, что опираться на подобные механизмы можно только тогда, когда в точности знаешь реакцию данной ОС на CLI/STI.
И работать, мне кажется, они будут медленнее Interlocked*, уже "забаненных" в первом сообщении за свою за неторопливость.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Oct 7 2009, 07:42
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(KolyanV @ Oct 7 2009, 00:24) *
Ничего не скажу по архитектуре блекфина, но приведенный Вами фрагмент мало о чем говорит. Насколько атомарна выполняемая там операция зависит от того, как компилятор его переведет в машиный код.


Переменная объявлена как volatile. Предпологаю, что процессор не имеет права сгенерить несколько машинных инструкций чтения из внешней памяти для одной Си операции чтения.
А то факт, что вместо одного чтения из внешней памяти происходило два - могу объяснить только прерыванием текущей операции чтения из внешней памяти, выполнением ISR, и повторным выполнением операции чтения
Go to the top of the page
 
+Quote Post
Oldring
сообщение Oct 7 2009, 10:32
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874



Цитата(sysel @ Oct 2 2009, 11:33) *
Пишу многопоточную программу под х86 процессор (защищенный режим) на С++.
Есть глобальная переменная (назовём её Count) для взаимодействия двух потоков. (в обоих потоках присутствуют операции чтение, запись и чтение-модификация-запись (Count=Count+A)).


Под Виндами правильно пользоваться Interlocked функциями Win32 API, такими как InterlockedIncrement. Код будет гарантированно переносимыми на другие платформы.

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


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Oct 7 2009, 10:56
Сообщение #11


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(Oldring @ Oct 7 2009, 14:32) *
Правильное решение на x86 ассемблере - использовать команду с префиксом lock.


Что-то сомнительно. Префикс LOCK блокирует шину только на время выполнения данной инструкции, поэтому здесь это не поможет, поскольку "порча" происходит во время прерывания между соседними инструкциями. Кроме того, у меня противоречивые сведения о том, распространяются ли привилегии на префикс LOCK или нет.
Go to the top of the page
 
+Quote Post
Oldring
сообщение Oct 7 2009, 11:56
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874



Цитата(Xenia @ Oct 7 2009, 14:56) *
Что-то сомнительно. Префикс LOCK блокирует шину только на время выполнения данной инструкции, поэтому здесь это не поможет, поскольку "порча" происходит во время прерывания между соседними инструкциями. Кроме того, у меня противоречивые сведения о том, распространияются ли привилегии на префикс LOCK или нет.


Инструкция, разумеется, должна быть одна, а именно, инкремента ячейки памяти командами lock add или lock xadd. Более сложные атомарные конструкции всегда можно сконструировать при помощи lock cmpxchg и цикла.

См. IA32 Instruction Set Reference

Кстати, борющимся за скорость будет полезно ознакомиться вот с этой статьей из MSDN

http://msdn.microsoft.com/en-us/library/2ddez55b(VS.71).aspx


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th June 2025 - 13:36
Рейтинг@Mail.ru


Страница сгенерированна за 0.01471 секунд с 7
ELECTRONIX ©2004-2016