Текущий архив: 2007.10.07;
Скачать: CL | DM;
Вниз
TThread ы и проблемы с ними же Найти похожие ветки
← →
Mitrofan (2007-07-24 01:51) [0]Доброй ночи, коллеги.
Не пойму почему виснет следующий код.
TaskThread = class(TThread)
private
protected
procedure Execute; override;
public
ThreadNumber: Integer;
i1,i2: Integer;
end;
var
threads: array [0..1] of TaskThread;
events: array [0..1] of TEvent;
procedure TaskThread.Execute;
var s: Double;
i: Integer;
begin
FreeOnTerminate:=true;
repeat
for i:=i1 to i2 do begin
end;
events[ThreadNumber].SetEvent;
Suspend;
until Terminated;
end;
procedure TForm1.Button1Click(Sender: TObject);
const N = 2000;
var K, i, middle: Integer;
t0,t1: Cardinal;
begin
Randomize;
threads[0]:=TaskThread.Create(true);
threads[0].ThreadNumber:=0;
events[0]:=TEvent.Create(nil, true, true, "");
threads[1]:=TaskThread.Create(true);
threads[1].ThreadNumber:=1;
events[1]:=TEvent.Create(nil, true, true, "");
K:=10000;
t0:=GetTickCount;
for i:=0 to N do begin
middle:= (K div 2) - 1;
threads[0].i1:=0;
threads[0].i2:=middle;
events[0].ResetEvent;
threads[1].i1:=middle+1;
threads[1].i2:=K-1;
events[1].ResetEvent;
threads[0].Resume;
threads[1].Resume;
events[0].WaitFor(INFINITE);
events[1].WaitFor(INFINITE);
end;
t1:=GetTickCount;
threads[0].Terminate;
threads[1].Terminate;
ShowMessage("Ok "+IntToStr(t1-t0));
Идея очень простая. Создаются две нити в программе.
Затем в цикле распределяется равномерно на них некоторый объем вычислений. После выполнения которого нить засыпает, до того момента пока ее не разбудять для обработки следующей порции данных. И так в цикле продолжается.
Подскажите, в чем я не прав. Запускаю на двухядерном ноутбуке и все ... виснет...
← →
Сергей М. © (2007-07-24 08:34) [1]Что показывает отладчик ?
← →
sniknik © (2007-07-24 09:07) [2]это не проблемы с потоками, это проблемы с логикой...
линейное программирование не совместимо с "событийным"... а у тебя именно линейное, вся "программа" в один столбик. в цикле стоит бесконечное ожидание события... и удивление а почему дальше то не проходит, виснет?
а вот потому, не делается так. вообще просто вставить потоки в программу это не панацея, нужно вставлять к месту и со знанием дела, как это работает... чтобы знать нужно предварительно почитать чего нибудь, а не просто писать абы что (просто набор операторов), и после в форум "помогите не работает", а и не должно при таком подходе.
> Запускаю на двухядерном ноутбуке и все ... виснет...
да хоть на 4-8-х ядерном, это не устраняет безграмотности. книги вот что поможет (не все правда... вспоминая Фленова и Архангельского... ;).
← →
Однокамушкин (2007-07-24 11:00) [3]На очередной итерации цикла у вас в главной нити threads[N].Resume может выполниться раньше, чем в соответствующей нити выполнится suspend... Для простоты предположим, что у нас только одна нить TaskThread, а не две... В общем, представьте ситуацию: главная нить висит на WaitFor, тут событие происходит, неглавная нить теряет квант времени, его получает главная, выходит из WaitFor, идёт на начало цикла, выполняет назначения, вызывает threads[0].Resume, снова доходит до WaitFor и переходит в режим ожидания... Квант времени снова переходит неглавной нити, а она только-только вышла из events[ThreadNumber].SetEvent, дальше она выполняет Suspend и тоже переходит в режим ожидания... всё, дедлок, обе нити висят и каждая ждёт сигнала от другой...
← →
Mitrofan (2007-07-24 11:14) [4]Хорошо, в таком случае как следует поступить ?
Как вы посоветуете организовать логику работы ?
Задача поста - нужна распараллелить цикл по количеству нитей
for i:=0 to N do begin
...
end.
← →
Однокамушкин (2007-07-24 11:18) [5]
> Mitrofan (24.07.07 11:14) [4]
> Хорошо, в таком случае как следует поступить ?
Отказаться от Suspend/Resume, а тоже будить нить по событию - даже если в главной нити SetEvent будет вызван раньше, чем WaitFor в неглавной, проблем не возникнет...
← →
Сергей М. © (2007-07-24 11:48) [6]TTaskData = тип данных для обработки;
TTaskResult = тип результата обработки;
TNewTaskEvent = procedure(Sender: TObject; var Data: TTaskData; var HasData: Boolean) of object;
TTaskResultEvent = procedure(Sender: TObject; Data: TTaskResult) of object;
TTaskThread = class(TThread)
private
FGetTask: TNewTaskEvent;
FDone: TTaskResultEvent;
FHasData: Boolean;
FData: TTaskData;
FResult: TTaskResult;
procedure DoNewTask;
procedure DoTaskResult;
protected
procedure Execute; override;
public
constructor Create(OnGetTask: TNewTaskEvent; OnDoneTask: TTaskResultEvent);
end;
constructor TTaskThread.Create(OnGetTask: TNewTaskEvent; OnDone: TTaskResultEvent);
begin
FGetTask := OnGetTask;
FDone := OnDoneTask;
inherited Create(False);
end;
procedure TTaskThread.DoNewTask;
begin
FHasData := False;
FGetTask(Self, FData, FHasData);
if not FHasData then Terminate;
end;
procedure TTaskThread.DoTaskResult;
begin
FDone(Self, FResult);
end;
procedure TTaskThread.Execute;
begin
FreeOnTerminate:=true;
while not Terminated do begin
Synchronize(DoNewTask);
if Terminated then Exit;
... обработка данных, указанных в FpData
... формирование результата обработки в FResult
Synchronize(DoTaskResult);
end;
← →
Сергей М. © (2007-07-24 12:08) [7]TForm1 = class(TForm)
..
procedure DoNewTask(Sender: TObject; var Data: TTaskData; var HasData: Boolean);
procedure DoTaskResult(Sender: TObject; Data: TTaskResult);
..
end;
procedure TForm1.DoNewTask;
begin
if ЕстьНовыеЗадания then
Data := ...данные для обработки потоком Sender
HasData := True;
end;
end;
procedure TForm1.DoTaskResult;
begin
.. в Data - результаты выполнения задания потоком Sender ..
end;
Страницы: 1 вся ветка
Текущий архив: 2007.10.07;
Скачать: CL | DM;
Память: 0.47 MB
Время: 0.033 c