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

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

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

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

Сообщение avi9526 » 28.07.2013 01:19:12

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

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

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

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


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

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

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

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

Сообщение SSerge » 28.07.2013 06:13:08

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

По теории, должно быть использовано это: http://ru.wikipedia.org/wiki/%D0%9C%D1% ... 0%BA%D1%81
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

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

Сообщение B4rr4cuda » 28.07.2013 09:38:27

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;
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

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

Сообщение hinst » 28.07.2013 11:51:37

Следует сделать с критическими секциями
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

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

Сообщение avi9526 » 29.07.2013 03:05:52

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

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

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

Сообщение iN0k » 29.07.2013 16:51:24

основная опасность в строке
Код: Выделить всё
Run := 1;
, в нее может попасть ОДНОВРЕМЕННО несколько потоков.

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

потоко-безопасность будет обеспечена, скорость выполнения соизмерима с критическими сессиями.
iN0k
постоялец
 
Сообщения: 146
Зарегистрирован: 18.07.2012 14:09:50

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

Сообщение Mirage » 30.07.2013 22:41:05

У такой реализации мьютекса масса проблем - и кэширование тут мешается и изменения порядка выполнения инструкций процессором, а если бы был продвинутый оптимизирующий компилятор, то и он бы менял порядок выполнения.
Можно реализовать с помощью функций interlockedExchange().
А вообще, конечно, в язык надо добавить синхронизированные блоки/функции. Тогда б можно было просто пометить функцию специальным ключевым словом.
Однако, всякие бездарные хелперы проще добавлять, чем что-то полезное, так что...
Еще кроссплатформенному языку необходим механизм, гарантирующий видимость изменений разными потоками.
Т.е. набор правил, которые описывают что нужно сделать, чтобы изменения переменной, сделанные в одном потоке, были гарантировано видны в другом. И в какой именно момент они будут видны.
Иначе о lock/wait-free алгоритмах можно забыть, а на одних критических секциях далеко не уедешь.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

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

Сообщение runewalsh » 30.07.2013 23:09:21

Mirage
Разве Interlocked... операции не гарантируют барьер? А без них (или явных барьеров — они в RTL есть) никакую очерёдность / видимость независимых изменений нельзя предполагать вовсе. Могу ошибаться.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

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

Сообщение Mirage » 31.07.2013 00:51:38

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

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

Сообщение avi9526 » 31.07.2013 03:53:38

Уважаемые, не найдётся ли у Вас какого-нибудь простенького примера с реализацией описанного вами подхода, потому как официальная документация, увы, обделена примерами, а без примера теория плохо идёт…
Аватара пользователя
avi9526
новенький
 
Сообщения: 16
Зарегистрирован: 25.08.2010 17:10:26

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

Сообщение runewalsh » 31.07.2013 09:45:30

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

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

Так, в твоём примере строка
Код: Выделить всё
if Run = 0 then

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

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

Сообщение Mirage » 31.07.2013 14:33:17

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


См. пост B4rr4cuda, там то, что в твоём случае нужно.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru
cron