Простое предотвращение выполнения функции в разных потоках

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Ответить
Аватара пользователя
avi9526
новенький
Сообщения: 16
Зарегистрирован: 25.08.2010 17:10:26

Простое предотвращение выполнения функции в разных потоках

Сообщение avi9526 »

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

К сожалению смутно понимаю многопоточность… со всякими там критическими секциями связываться не охота. Надо как можно проще предотвратить одновременное выполнение функции в двух потоках.

Пока решил сделать с помощью переменной (объявленной вне функции), типа

Код: Выделить всё

function MyClass.Something(arg1: Integer): Boolean;
  begin
    if Run = 0 then
      begin
      Run := 1;
      // здесь основной код функции
      Run := 0;
      end;
  end;


Правда здесь (как я понял) нет гарантии, что функция не будет вызвана одновременно несколько раз.

Подскажите пожалуйста

Спасибо!
SSerge
энтузиаст
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Сообщение SSerge »

Я таким образом пытался предотвратить исполнение кода, вызываемого разными таймерами. НЕ РАБОТАЕТ. То есть, последствия совершенно непредсказуемые, со сбоями. Даже по теории, чтобы было работоспособно, необходимо заставить компилятор сформировать внешнюю переменную так, чтобы она не была кэширована и запись в нее производилась немедленно. Для современных процессоров на такое поведение рассчитывать не стоит.

По теории, должно быть использовано это: http://ru.wikipedia.org/wiki/%D0%9C%D1% ... 0%BA%D1%81
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

avi9526 писал(а):со всякими там критическими секциями связываться не охота

Совершенно зря, так как это очень просто и стабильно работает.

Если вкратце то методика следующая - обьявляете переменную типа TCriticalSection, создаете в конструкторе, уничтожаете в деструкторе. В нужном месте входите в критическую секцию и покидаете секцию при завершении.
Кусок кода в критической секции будет выполняться только одним потоком. Остальные ждут. Первый завершил - пошел следующий. И тд.

Используя ваш же пример будет выглядеть так:

Код: Выделить всё

Myclass=class(..)
private
FCrt:TCriticalSection;
...

constructor MyClass.Create;
begin
FCrt:=TCriticalSection.create;
end;

destructor MyClass.Destroy;
begin
  Freeandnil(FCrt);
end;

function MyClass.Something(arg1: Integer): Boolean;
begin
  FCrt.Enter;
     // здесь основной код функции
  FCrt.Leave;   
end;
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

Следует сделать с критическими секциями
Аватара пользователя
avi9526
новенький
Сообщения: 16
Зарегистрирован: 25.08.2010 17:10:26

Сообщение avi9526 »

Ок, спасибо SSerge, важно было знать почему не заработает.
И другим тоже спасибо, воспользуюсь крит-ой секц-ей…

Решено!
iN0k
постоялец
Сообщения: 146
Зарегистрирован: 18.07.2012 14:09:50

Сообщение iN0k »

основная опасность в строке

Код: Выделить всё

Run := 1;
, в нее может попасть ОДНОВРЕМЕННО несколько потоков.

именно в Вашем случае (т.е. исключая ожидание освобождения функции) можно воспользоваться и "внешней" глобальной переменной, только пользоваться ей надо с помощью interlock ф-ий.

потоко-безопасность будет обеспечена, скорость выполнения соизмерима с критическими сессиями.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

У такой реализации мьютекса масса проблем - и кэширование тут мешается и изменения порядка выполнения инструкций процессором, а если бы был продвинутый оптимизирующий компилятор, то и он бы менял порядок выполнения.
Можно реализовать с помощью функций interlockedExchange().
А вообще, конечно, в язык надо добавить синхронизированные блоки/функции. Тогда б можно было просто пометить функцию специальным ключевым словом.
Однако, всякие бездарные хелперы проще добавлять, чем что-то полезное, так что...
Еще кроссплатформенному языку необходим механизм, гарантирующий видимость изменений разными потоками.
Т.е. набор правил, которые описывают что нужно сделать, чтобы изменения переменной, сделанные в одном потоке, были гарантировано видны в другом. И в какой именно момент они будут видны.
Иначе о lock/wait-free алгоритмах можно забыть, а на одних критических секциях далеко не уедешь.
Аватара пользователя
runewalsh
энтузиаст
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Сообщение runewalsh »

Mirage
Разве Interlocked... операции не гарантируют барьер? А без них (или явных барьеров — они в RTL есть) никакую очерёдность / видимость независимых изменений нельзя предполагать вовсе. Могу ошибаться.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

Гарантируют вроде, по крайней мере на x86.
Однако, часто жирновато их вызывать, если надо просто проверить значение.
Наличие явных барьеров хорошо (не знал), но цельный механизм, связывающий барьеры, обращения к памяти и синхронизацию воедино, куда удобнее.
Аватара пользователя
avi9526
новенький
Сообщения: 16
Зарегистрирован: 25.08.2010 17:10:26

Сообщение avi9526 »

Уважаемые, не найдётся ли у Вас какого-нибудь простенького примера с реализацией описанного вами подхода, потому как официальная документация, увы, обделена примерами, а без примера теория плохо идёт…
Аватара пользователя
runewalsh
энтузиаст
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Сообщение runewalsh »

Ты б пост B4rr4cuda прочитал, чудик. ;3

> К сожалению смутно понимаю многопоточность… со всякими там критическими секциями связываться не охота.
Без критических секций твой многопоточный код — одна сплошная гонка.
http://ru.wikipedia.org/wiki/%D0%A1%D0% ... 0%BA%D0%B8

Так, в твоём примере строка

Код: Выделить всё

if Run = 0 then

может выполниться несколькими экземплярами функции одновременно и в обоих проверка пройдёт, но проявится такая ошибка в одном случае из 1000.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

avi9526 писал(а):Уважаемые, не найдётся ли у Вас какого-нибудь простенького примера с реализацией описанного вами подхода, потому как официальная документация, увы, обделена примерами, а без примера теория плохо идёт…


См. пост B4rr4cuda, там то, что в твоём случае нужно.
Ответить