Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Потоки и синхронизация вызовов функций из dll


Автор: Loony 25.5.2008, 21:19
Добрый вечер, Уважаемые! Скажу сразу, с Delphi не очень дружу, могу сморозить чушь! smile Тема заезженная, но поиском по форуму я вразумительного ответа не получил! Возникла такая задача: есть длл, в ней зашиты функции для получения определенных данных из сети. К длл необходимо обращаться из множества потоков, т.е. необходимо чтобы в один момент времени функцию вызывал только один поток, кроме того, нужно обновлять данные на форме в зависимости от значения, полученного из функции в длл. Сначала сделал просто через Synchronize, ну не знал я, что метод служит только для взаимодействия с основным потоком! smile Узнал, когда получил две одинаковые порции данных. Следующая мысль - это реализовать все при помощи "Critical Section", но дело в том, что в известной на этом сайте статье про многопоточность говорится, что вообще не рекомендуется надолго блокировать потоки, а у меня така ситуация возможна, т.к. длл может обратиться к сетевому ресурсу, который не ответит мгновенно!

Вопросы:
1. Правльным ли будет использовать в моем случае критические секции?
2. Если нет, то что надо использовать!?
3. Чем грозит длительная блокировка потока и грозит ли чем-то вообще?
4. Возможно при использовании Delphi с потоками есть еще какие-то ньюансы?

P.S. Delphi 7, если это важно!

Автор: Alexeis 25.5.2008, 22:30
Цитата(Loony @  25.5.2008,  20:19 Найти цитируемый пост)
3. Чем грозит длительная блокировка потока и грозит ли чем-то вообще?

  Ни чем не грозит кроме ожидания. Блокировать доступ нужно ко всем функциям или только к той конкретной, которая используется в текущий момент? Если только текущую, то можно сделать несколько критических секций для каждой функции.

Автор: Loony 25.5.2008, 22:48
То есть, на первый вопрос ответ - да!? smile Вообще надо так: сначала вызывается функция  для генерации уникальных данных, потом функция, которая должна эти данные передать и вернуть результат! Блокировать значит нужно обе, т.е. входим в критическую секцию, выполняем подряд две функции, получаем результат. Для отдельных функций делать критическуие секции думаю не стоит, не знаю даже, смысла не вижу. Может еще будут  советы по реализации!?

Автор: Alexeis 26.5.2008, 13:39
Цитата(Loony @  25.5.2008,  21:48 Найти цитируемый пост)
ля отдельных функций делать критические секции думаю не стоит, не знаю даже, смысла не вижу. Может еще будут  советы по реализации!? 

  Я имел ввиду разместить критическую секцию внутри функции. Представь, что функцию вызываешь из разных модулей, тогда критическую секцию прийдеться объявлять в одном из общих модулей, да и забыть вставить ее можно случайно, а если критическую секцию вставить в функцию, то во первых понадобиться всего одна критическая секция во вторых, когда второй поток попытается вызвать функцию, то он зайдет и автоматом заблокируется. 
  Есть еще вариант сделать мьютекс с таймаутом. Т.е. второй поток зайдет в функцию подождет 100мс, увидит что ждать нужно долго и выйдет досрочно с специальным кодом ошибки, после чего сможет делать что-то другое и повторить попытку через некоторое время.

Автор: Loony 26.5.2008, 14:07
Alexeis, если имеется ввиду внутри функции длл, то сделать этого не получится, исходников длл нет.

Автор: Felan 26.5.2008, 14:20
Неважно. Можно сделать модуль-обертку, где будут просто вызываться нужные функции из длл + синхронизация.
От себя добавлю, что синхронизировать нужно только доступ к данным, причем, когда существует доступ на изменения.
Синхронизировать доступ на чтение к данным которые не изменяются не имеет смысла.
Синхронизировать функции генерации чего-либо, если при генерации не используются глобальные данных, которые существуют И изменяются между вызовами таких функций, тоже синхронизировать смысла нет.

Автор: Rennigth 26.5.2008, 15:07
Цитата(Felan @  26.5.2008,  14:20 Найти цитируемый пост)
Синхронизировать доступ на чтение к данным которые не изменяются не имеет смысла.

эт ты зря...

Автор: Alexeis 26.5.2008, 15:39
Цитата(Rennigth @  26.5.2008,  14:07 Найти цитируемый пост)
эт ты зря... 

  Это еще почему? По моему синхронизация не нужна даже при условии что открывается только доступ для чтения. Важно чтобы не было даже косвенного влияния того что читается на то что пишется. Гарантия неизменности это дополнительное необязательное условие.
  Представим себе ситуацию. На сервер непрерывно поступают данные о прогнозе погоды по разным регионам. Существует много служб, которые достают эти данные и публикуют у себя. Ситуация что в прогноз на хабаровск будет текущий, а на Москву будет за прошлый час устраивает всех. Тем не менее, общий прогноз находиться на стадии записи, тогда как доступ к отдельным записям доступен всегда. 
  Если есть гарантия неизменности то вообще идеально... 

Автор: Loony 26.5.2008, 16:24
Felan, обертки уже сделал! smile Всем спасибо!

Автор: Rennigth 26.5.2008, 16:58
Alexeis, а что получится если два потока будут одновременно читать из одного места?
* ушел читать rtfm... но мне всегда казалось что... 

Автор: Alexeis 26.5.2008, 17:15
Цитата(Rennigth @  26.5.2008,  15:58 Найти цитируемый пост)
Alexeis, а что получится если два потока будут одновременно читать из одного места?

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

Автор: Felan 27.5.2008, 07:29
Цитата(Rennigth @  26.5.2008,  18:58 Найти цитируемый пост)
Alexeis, а что получится если два потока будут одновременно читать из одного места?
* ушел читать rtfm... но мне всегда казалось что...  

Ниче не будет. Оба прочитают и все. Если используются примитивные типы, то скорее всего ничего не будет даже если третий будет одновременно писать, а вот если классы, стринги, записи и т.п., то может получится так, что один поток начал писать, а второй начал читать, первый притормозил, а второй прочитал мусор...

Цитата(Alexeis @  26.5.2008,  19:15 Найти цитируемый пост)
  Такое происходит и постоянно. Например флаги мьютекса или семафора. К ним же происходит обращение из нескольких потоков, тот же счетчик семафора. Физически память не позволит одновременно обратиться даже при двух процах, потому это в любом случае будет последовательно. 

Ты не путай, это специальные объекты, доступ к которым контролирует система. А к память как раз даже очень позволяет обращаться одновременно из разных потоков. Для этого и существует синхронизация.

Автор: Alexeis 27.5.2008, 07:59
Цитата(Felan @  27.5.2008,  06:29 Найти цитируемый пост)
Ты не путай, это специальные объекты, доступ к которым контролирует система. А к память как раз даже очень позволяет обращаться одновременно из разных потоков. Для этого и существует синхронизация. 

  И чем же системам ограничивает? Там просто атомарные типы отвечают за состояние, потому если один записал true, то другой не сможет прочитать что-то на середине записи состояния true. 

Цитата(Felan @  27.5.2008,  06:29 Найти цитируемый пост)
а вот если классы, стринги, записи и т.п., то может получится так, что один поток начал писать, а второй начал читать, первый притормозил, а второй прочитал мусор...

  Ну тут все зависит организации самого доступа и что считать противоречивым состоянием. Это определяется в каждом конкретном случае отдельно. Излишняя синхронизация тоже вредна, более того она может приводить самоблокировке системы там где можно было без этого обойтись.

Автор: Felan 27.5.2008, 08:50
Цитата(Alexeis @  27.5.2008,  09:59 Найти цитируемый пост)
  И чем же системам ограничивает? Там просто атомарные типы отвечают за состояние, потому если один записал true, то другой не сможет прочитать что-то на середине записи состояния true. 

Внутренними правилами ограничивает. Не путай системные спец. объекты и доступ к памяти.

Цитата(Alexeis @  27.5.2008,  09:59 Найти цитируемый пост)
  Ну тут все зависит организации самого доступа и что считать противоречивым состоянием. Это определяется в каждом конкретном случае отдельно. Излишняя синхронизация тоже вредна, более того она может приводить самоблокировке системы там где можно было без этого обойтись. 

Тут все зависит от везения. Т.к. resume останавливает поток в произвольном месте между процессорными инструкциями, и если запись данных занимает болше одной инструкции, то вероятна ситуация, когда записано только половина данных. И вероятность пропорциональна количеству потоков и частоте обращений.
Поэтому и рекомендуется явно выделять точки ожидания для потока.

Что такое самоблокировка? Если криво сделана синхронизация, так, что она приводит к дедлоку, то это именно криво сделанная синхронизация. Само обычно ничего не бывает smile

Автор: Alexeis 27.5.2008, 11:14
Цитата(Felan @  27.5.2008,  07:50 Найти цитируемый пост)
Что такое самоблокировка? Если криво сделана синхронизация, так, что она приводит к дедлоку, то это именно криво сделанная синхронизация. Само обычно ничего не бывает

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

Автор: Felan 27.5.2008, 11:31
Цитата(Alexeis @  27.5.2008,  13:14 Найти цитируемый пост)
  Например потоки работают с 2мя записями. Для этого она захватывает одну и ждет вторую, в это время второй поток захватил вторую и ждет первую, которую занял первый. Таким образом 2 потока ждут друг друга. Возможны и другие более сложные ситуации с косвенной связью, потому избыточная синхронизация также вредна как и недостаточная.  

Это называется Deadlock. И это значит, что неправильно сделана синхронизация в принципе. Избыточная синхронизация грозит только уменьшением производительности. И уж тем более это происходит не само, так что про САМОблокировке и речи быть не может ;)

Автор: bems 27.5.2008, 17:18
Цитата(Loony @  25.5.2008,  21:19 Найти цитируемый пост)
Следующая мысль - это реализовать все при помощи "Critical Section", но дело в том, что в известной на этом сайте статье про многопоточность говорится, что вообще не рекомендуется надолго блокировать потоки
В этом случае полезно TryEnterCriticalSection

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)