Модераторы: Snowy, MetalFan, bems, Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Потоки и события, зависание до процедуры синхронизации 
:(
    Опции темы
Dom
Дата 7.12.2008, 23:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 3
Всего: 4



Первый опыт работы с потоками. Случай конечно не самый простой. Простые уже рассмотрел и вроде как чуток разобрался. Тем кто посоветует классиков сразу скажу - Петровича читал, и по форуму лазил, ну и в инете само собой. Белые пятна присутствуют, но среди них есть и островки знаний. То что в приведенном ниже коде возможно каша, можно нне упоминать. Лучше просто указать где и как от нее избавиться хотя бы. smile

Итак, приступим. Есть программа, в которой можно построить набор матмоделей №1 (или вообще всего одну). Каждая матмодель включает в себя набор других моделей №2 попроще что ли (их число может быть очень большим). Расчет моделей №2 происходит независимо друг от друга, все что у них есть общего это обращение к единому блоку с данными. Т.е. на лицо случай, когда параллельное вычисление этих моделей №2, должно дать существенный прирост в производительности на много ядерных (многопроцессорных) системах в первую очередь.

Цель такова - строить модели №2 каждую в отдельном потоке. По возможности одновременно должно запускаться не слишком большое число потоков (пока не могу понять как это реализовать, возможно через семафоры, а?), т.к. их возможное число может быть свыше тысячи. Т.е. хорошо бы задавать максимально число одновременно активных потоков. После расчета всех моделей №2 должен следовать этап расчета их статистики в рамках более общей модели №1, в которую они входят. Т.е. в этом случае надо дождаться пока все потоки завершат свою работу, затем расчитать статистику получившейся общей модели №1, затем запустить построение следующей матмодели №1.

Покажу на схематичном примере, первую попытку реализации вышеизложенного.

Есть глобальная переменная ThreadsCount, которая содержит число существующих потоков. Есть событие EndCalcEvent, которое по идее должно срабатывать когда число существующих потоков становится равным нулю.
Из главной формы запускается процедура постоения матмоделей №1 (определены как F). Создаем первый объект F и запускем процедуру вычислений, которая состоит из расчета большого числа отдельных небольших моделей №2 (обозначены как Т). Создаем нужное число моделей Т, одновременно создаем соответствующие им потоки, производим настойки потоков и запускаем их. В тестовом режиме запускал таким образом, чтобы число объектов Т было равно 1. После этого дебаг переходит на строку if EndCalcEvent.WaitFor(INFINITE) = wrSignaled. А затем попадаем в сам поток. В котором все происходит все корректно, до момента синхронизации полученных результатов. После перехода на строку Synchronize(Update) жму Ф7 или Ф8 и все, дальше непонятно что происходит, в процедуру Update не заходит. Просто стоит и ждет чего-то. Есть подозрение что намудрил чего-то с событиями. Если вместо EndCalcEvent.WaitFor(INFINITE) написать EndCalcEvent.WaitFor(20000), то через какое-то время ни с то ни с сего запускается F.CalcStat (при чем брейкпоинт стоящий на этой строке не срабатывает, зато вываливается ошибка расчета, т.к. объект F по сути еще пустой). После чего я попадаю в процедуру Update потока.

Delphi 7
Код

var
ThreadsCount: integer;  // при создании формы задается = 0, следит за общим числом запущенных потоков
CS: TTMultiReadExclusiveWriteSynchronizer;
EndCalcEvent: TEvent;  // создается при создании формы EndCalcEvent := TEvent.Create(nil, false, false, '');


procedure MainForm.Start(Count: integer);
var
i: integer;
F: TClassF;
begin
  for i := 1 to N do     // число N как правило невелико
  begin
    F := TClassF.Create;  // создаем объект F
    F.StartCalc(Count);   // запускаем расчет
    if EndCalcEvent.WaitFor(INFINITE) = wrSignaled then
    begin
      F.CalcStat;         // подсчитываем статистику
      List2.Add(F);       // добавляем объект в список
    end;
  end;
  List2.Show;             // вывод списка на форму
end;




procedure TClassF.StartCalc(Count: integer);
var
i: integer;
T: TClassT;
MyThread: TMyThread;
begin
  EndCalcEvent.ResetEvent;
  for i := 0 to count - 1 do
  begin
    T := TClassT.Create;    // создаем объект Т
    List1.Add(T);           // добавляем его с список
    MyThread := TMyThread.Create(T);   // поток создается приостановленным 
    MyThread.FreeOnTerminate := true;
    inc(ThreadsCount);      // увеличиваем число запущенных потоков на 1
    MyThread.OnTerminate := DecreaseCounter;  
    MyThread.Resume;
  end;
end;


procedure TClassF.DecreaseCounter(Sender: TObject);   // сюда даже не заходит
begin
  CS.BeginWrite;          // зачем тут кртическая секция? сам не знаю, но такой код был в хелпе
  dec(ThreadsCount);      // уменьшаем счетчик числа запущенных потоков на 1
  if ThreadsCount = 0 then  
    EndCalcEvent.SetEvent;  // устанавливаем событие, если все потоки завершены
  CS.EndWrite;
end;




procedure TMyThread.Execute;
begin
  while (LocalT.X = 0) and (not Terminated) do
    LocalT.CalcX;
  Synchronize(Update);   // из цикла while выходит, становится на эту строку и дальше любой шаг Ф7/Ф8 
//вызывает полное отсутствие реакции, в саму процедуру Update ни разу не заходит
end;


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

Буду благодарен любым конструктивным советам и подсказкам, а то замучился уже.
Советы читать маны неактуальны, т.к. именно этим и занимаюсь. smile Рано или поздно и сам конечно соображу где был неправ, но хотелось бы чтобы ткнули или предложили более действенный алгоритм, а то изыскания могут затянуться.

ЗЫ, Понимаю, что одна тема - один вопрос. Но процедура ТEvent.WaitFor вызывает остановку потока, в котором она вызывается? Т.е. если ее вызывать в главном потоке, то главная форма приложения зависнет тоже?

Это сообщение отредактировал(а) Dom - 7.12.2008, 23:26
PM MAIL   Вверх
CodeMonkey
Дата 8.12.2008, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



У вас, насколько я понял, главный поток висит в WaitFor, а вторичный вызывает Synchronize. Получается взаимная блокировка: вторичный поток ждёт главный, а главный - вторичный. Как работает Synchronize
Посмотрите также реализацию TThread.WaitFor.

Добавлено через 1 минуту и 49 секунд
Цитата(Dom @  7.12.2008,  23:00 Найти цитируемый пост)
Вкратце. Требуется одновременный запуск ограниченного числа потоков, чтобы при завершении одного потока начинал работать следующий.

Зачем несколько потоков? Обычно такое делается одним потоком, у которого есть очередь заданий. Поток последовательно выполняет задания из очереди.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Dom
Дата 8.12.2008, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 3
Всего: 4



Про зависание главного потока после вызова TEvent.WaitFor догадался. Т.е. эта процедура и для потока и для события действует одинаково - погружая поток в ожидание, так?

Цитата(CodeMonkey @  8.12.2008,  10:11 Найти цитируемый пост)
Зачем несколько потоков? Обычно такое делается одним потоком, у которого есть очередь заданий. Поток последовательно выполняет задания из очереди.
Вот это не совсем понял, но поищу что-то по этим ключевым словам. Спасибо за наводку! Будем копать дальше. smile
PM MAIL   Вверх
CodeMonkey
Дата 8.12.2008, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(Dom @  8.12.2008,  11:21 Найти цитируемый пост)
Т.е. эта процедура и для потока и для события действует одинаково - погружая поток в ожидание, так?

В том-то и дело, что по-разному. У объекта "событие" WaitFor погружает поток в безусловное ожидание события. У потока - нет. Я вам и подсказал посмотреть реализацию WaitFor потока.

Рекомендую пройти тест ;)

Может ещё будет интересно это.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0876 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.