![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как разрулить работу потока в вызовах его методов? [D7, WinXP]
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 может измениться