Страница 1 из 1
Простое предотвращение выполнения функции в разных потоках
Добавлено:
28.07.2013 01:19:12
avi9526
Здравствуйте!
К сожалению смутно понимаю многопоточность… со всякими там критическими секциями связываться не охота. Надо как можно проще предотвратить одновременное выполнение функции в двух потоках.
Пока решил сделать с помощью переменной (объявленной вне функции), типа
- Код: Выделить всё
function MyClass.Something(arg1: Integer): Boolean;
begin
if Run = 0 then
begin
Run := 1;
// здесь основной код функции
Run := 0;
end;
end;
Правда здесь (как я понял) нет гарантии, что функция не будет вызвана одновременно несколько раз.
Подскажите пожалуйста
Спасибо!
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
28.07.2013 06:13:08
SSerge
Я таким образом пытался предотвратить исполнение кода, вызываемого разными таймерами. НЕ РАБОТАЕТ. То есть, последствия совершенно непредсказуемые, со сбоями. Даже по теории, чтобы было работоспособно, необходимо заставить компилятор сформировать внешнюю переменную так, чтобы она не была кэширована и запись в нее производилась немедленно. Для современных процессоров на такое поведение рассчитывать не стоит.
По теории, должно быть использовано это:
http://ru.wikipedia.org/wiki/%D0%9C%D1% ... 0%BA%D1%81
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
28.07.2013 09:38:27
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;
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
28.07.2013 11:51:37
hinst
Следует сделать с критическими секциями
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
29.07.2013 03:05:52
avi9526
Ок, спасибо SSerge, важно было знать почему не заработает.
И другим тоже спасибо, воспользуюсь крит-ой секц-ей…
Решено!
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
29.07.2013 16:51:24
iN0k
основная опасность в строке
- Код: Выделить всё
Run := 1;
, в нее может попасть ОДНОВРЕМЕННО несколько потоков.
именно в Вашем случае (т.е. исключая ожидание освобождения функции) можно воспользоваться и "внешней" глобальной переменной, только пользоваться ей надо с помощью interlock ф-ий.
потоко-безопасность будет обеспечена, скорость выполнения соизмерима с критическими сессиями.
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
30.07.2013 22:41:05
Mirage
У такой реализации мьютекса масса проблем - и кэширование тут мешается и изменения порядка выполнения инструкций процессором, а если бы был продвинутый оптимизирующий компилятор, то и он бы менял порядок выполнения.
Можно реализовать с помощью функций interlockedExchange().
А вообще, конечно, в язык надо добавить синхронизированные блоки/функции. Тогда б можно было просто пометить функцию специальным ключевым словом.
Однако, всякие бездарные хелперы проще добавлять, чем что-то полезное, так что...
Еще кроссплатформенному языку необходим механизм, гарантирующий видимость изменений разными потоками.
Т.е. набор правил, которые описывают что нужно сделать, чтобы изменения переменной, сделанные в одном потоке, были гарантировано видны в другом. И в какой именно момент они будут видны.
Иначе о lock/wait-free алгоритмах можно забыть, а на одних критических секциях далеко не уедешь.
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
30.07.2013 23:09:21
runewalsh
Mirage
Разве Interlocked... операции не гарантируют барьер? А без них (или явных барьеров — они в RTL есть) никакую очерёдность / видимость независимых изменений нельзя предполагать вовсе. Могу ошибаться.
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
31.07.2013 00:51:38
Mirage
Гарантируют вроде, по крайней мере на x86.
Однако, часто жирновато их вызывать, если надо просто проверить значение.
Наличие явных барьеров хорошо (не знал), но цельный механизм, связывающий барьеры, обращения к памяти и синхронизацию воедино, куда удобнее.
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
31.07.2013 03:53:38
avi9526
Уважаемые, не найдётся ли у Вас какого-нибудь простенького примера с реализацией описанного вами подхода, потому как официальная документация, увы, обделена примерами, а без примера теория плохо идёт…
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
31.07.2013 09:45:30
runewalsh
Ты б пост
B4rr4cuda прочитал, чудик. ;3
> К сожалению смутно понимаю многопоточность… со всякими там критическими секциями связываться не охота.Без критических секций твой многопоточный код — одна сплошная гонка.
http://ru.wikipedia.org/wiki/%D0%A1%D0% ... 0%BA%D0%B8Так, в твоём примере строка
- Код: Выделить всё
if Run = 0 then
может выполниться несколькими экземплярами функции
одновременно и в обоих проверка пройдёт, но проявится такая ошибка в одном случае из 1000.
Re: Простое предотвращение выполнения функции в разных поток
Добавлено:
31.07.2013 14:33:17
Mirage
avi9526 писал(а):Уважаемые, не найдётся ли у Вас какого-нибудь простенького примера с реализацией описанного вами подхода, потому как официальная документация, увы, обделена примерами, а без примера теория плохо идёт…
См. пост
B4rr4cuda, там то, что в твоём случае нужно.