Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как разрулить работу потока в вызовах его методов? [D7, WinXP]


Страницы:   1 2

Aleksandr. ©   (2005-02-11 15:12:00) 

Есть класс-наследник от TThread, имеющий свойство FList TList, в котором содержатся объекты с информацией для выполнения работы, метод AddQuery для добавления этих объектов в List, и метод,который работает внутри Execute:

type
 TQueryThread = class (TThread)
 private
    FList   : TList;
    FListCS : TCriticalSection;
    procedure DoQuery(aQuery : TExecQuery);
 public
    procedure AddQuery(aQuery : TExecQuery);
    procedure Execute; override;
    ...
 end;
   
procedure TQueryThread.AddQuery(aQuery : TExecQuery);
begin
 FListCS.Acquire;
 try
   FList.Add(aQuery)
 finally
   FListCS.Release
 end
end;

procedure TQueryThread.Execute;
var
 Q : TExecQuery;
begin
 repeat
   while GetQueryCount>0 do begin     // защищенный FListCS FList.Count
     FListCS.Acquire;
     try
       Q:=TExecQuery(FList.Items[0]);
       FList.Delete(0)
     finally
       FListCS.Release
     end;
     DoQuery(Q)
   end;
   Suspend
 until Terminated
end;

Код DoQuery приводить не буду, он очень большой и длительный по исполнению.
Есть также менеджер потоков TQueryThread, который, получая список из TExecQuery, раздает его по потокам:

procedure TQueryManager.ProcessQueries(L : TList);
var
 i, j : integer;
begin
 for i:=0 to L.Count-1 do begin
   for j:=0 to FQueryThreadList.Count-1 do
     if FQueryThreadList.Items[j].ID=TExecQuery(L.Items[i]).ID then begin
       FQueryThreadList.Items[j].AddQuery(TExecQuery(L.Items[i]));
       if FQueryThreadList.Items[j].Suspended then
         FQueryThreadList.Items[j].Resume;
       Break
     end
 end
end;


Вот вся эта схема время от времени дает длительные затыки. Лог выполнения показывает, что происходит примерно следующее:
Добавляется объект запроса в нить, она входит в метод DoQuery,
в это время добавляется еще один объект, и нить прекращает выполнять DoQuery. И обрабатывает все полученные объекты только тогда, когда перестанет вызываться AddQuery, возникнет пауза, а затем добавится еще один объект, добавление которого вызовет резюмирование нити. Может ли такое быть и как это можно разрулить? Догадываюсь, что есть вариант с блокировкой критической секцией между методами AddQuery и DoQuery, но он вызывает у меня сомнения, т.к. теряется смысл в FList, а метод DoQuery очень длительный.


Leonid Troyanovsky   (2005-02-12 03:29:00) [21]

> Aleksandr.   (12.02.05 02:17) [11]

> procedure TQueryThread.AddQuery(aQuery : TExecQuery);
> begin
>   FList.LockList.Add(aQuery);
>   FList.UnlockList
> end;

Просто FList.Add(aQuery).
И

procedure TQueryThread.Execute;
var
Q : TExecQuery;
begin
   while not Terminated do
     begin
       with FList.Lock do
         try
           if Count = 0 then
             Break; // завершаемся или выход на ожидание(?)
           Q:=TExecQuery(Items[0]);
           Delete(0);
         finally
           FList.UnLockList;
         end;
       DoQuery(Q); // внешние try опущены
       Q.Free; // Возможно, что требует Synchronize(..)
       // Suspend;
    end;
end;

И что за Suspend? Ecли нужна реакция на событие,
то WaitFor*Object, можно и без Terminated.

> Что это принципиально изменит?

А что принципиально?
Если нужна асинхронная обработка, то нужен пул потоков,
каждый из которых будет обрабатывать один TExecQuery.

--
Regards, LVT.


Aleksandr.   (2005-02-12 02:18:00) [22]

Млин...


Aleksandr.   (2005-02-12 02:17:00) [23]

Leonid Troyanovsky © :
Ну, все равно какое-то разруливание требуется, наверное. Пусть я заменю код на

procedure TQueryThread.AddQuery(aQuery : TExecQuery);
begin
  FList.LockList.Add(aQuery);
  FList.UnlockList
end;

procedure TQueryThread.Execute;
var
Q : TExecQuery;
begin
repeat
  while
    try
      Q:=TExecQuery(FList.LockList.Items[0]);
      FList.UnLockList;
      FList.LockList.Delete(0);
      FList.UnLockList
    DoQuery(Q)
  end;
  Suspend
until Terminated
end;

Что это принципиально изменит?


Leonid Troyanovsky   (2005-02-12 01:11:00) [24]


> Aleksandr.   (11.02.05 23:17) [9]

> Я, если честно, каких-то преимуществ TThreadList'a перед
> просто List'ом не увидел. Потому и не стал изгаляться.


TThreadList защищает свой список критической секцией.
Так что, более ничего и не требуется.

--
Regards, LVT.


Aleksandr.   (2005-02-11 23:17:00) [25]

Leonid Troyanovsky ©  :
Я, если честно, каких-то преимуществ TThreadList'a перед просто List'ом не увидел. Потому и не стал изгаляться.

Alexander Panov © :
Достаточно часто. В пиковые часы загрузки может и каждые 10 секунд вызываться.


Alexander Panov   (2005-02-11 21:51:00) [26]

Как часто у тебя вызывается
procedure TQueryManager.ProcessQueries(L : TList);
?


Leonid Troyanovsky   (2005-02-11 20:54:00) [27]


> Aleksandr.   (11.02.05 15:12)  
> Есть класс-наследник от TThread, имеющий свойство FList
> TList, в котором содержатся объекты с информацией для


TThreadList.

--
Regards, LVT.


Eraser   (2005-02-11 19:42:00) [28]

Aleksandr
если нить находится в процессе выполнения Execute, а ей кто-нибудь вызывает resume - что произойдет с текущего выполняющегося метода?


Этот метод продолжет выполнение...


Aleksandr.   (2005-02-11 18:10:00) [29]

Истчо вопрос на эту тему рождается: если нить находится в процессе выполнения Execute, а ей кто-нибудь вызывает resume - что произойдет с текущего выполняющегося метода? Он просто сбросится и нить вернется в начало цикла Execute?


Aleksandr.   (2005-02-11 15:54:00) [30]

Digitman ©  :
Не понял... Если Вы о FList, то он же является свойством нити и используется только в ее методах? Кем же он еще используется?


Digitman   (2005-02-11 15:47:00) [31]

список этот у тебя - ресурс используемый более чем одним тредом.
хоть на 2-процессорной, хоть на N-процессорной, но обращение к списку хоть по записи хоть по чтению д.б. защищено единым блоком обращения к крит.секции, а не несколькими последовательными


Aleksandr.   (2005-02-11 15:35:00) [32]

Digitman ©  :
То есть это все должно быть в критической секции? Но это же не критично - обращение идет к первому элементу FList а не последнему? Хотя на 2-процессорной машине, может, и имеет...


Digitman   (2005-02-11 15:23:00) [33]

первое же что коробит глаз - между GetQueryCount и FListCS.Acquire состояние списка FListCS может измениться


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо