Форум: "Основная";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];
Внизпомогите с разобраться с потоками Найти похожие ветки
← →
Zahar (2005-01-09 15:31) [0]Помогите плиз разобраться с потоками. Нашел кучу информации где разные потоки выполняют разные функции, а мне нужно чтобы все потоки выполняли одну и ту же операцию.
Задача дла примера:
Есть текстовый файл в котором N-строк с числами (для примера возьмем 300).
Каждый поток должен прочитать из этого файла по M-записей (например 50), проделать над ними определенные преобразования и записать в другой текстовый файл.
Таким образом, как я понимаю, динамически должно быть создано 6 потоков (300/50=6) каждый из которых возьмет свою часть записей из исходного файла:
Thread 1 - 1..50
Thread 2 - 51..100
Thread 3 - 101..150
Thread 4 - 151..200
Thread 5 - 201..250
Thread 6 - 251..300
Для примера каждое число нужно умножить на 2 и записать в конечный файл.
Т.е. функция для потока будет одна, но обрабатывать в каждом потоке она будет разные последовательности данных.
Помогие очень разобраться с этой задачей. В потоках я полный новичек.
Заранее благодарен за любую помощь.
← →
Zahar (2005-01-09 15:33) [1]Желательно использовать встроенный класс TThread.
← →
olookin © (2005-01-09 15:50) [2]Почему бы создании потоков не запоминать их ThreadID, а при выполнении функции указывать каждому потоку в зависимости от его ThreadID, какой участок файла ему прочитывать?
← →
Zahar (2005-01-09 15:54) [3]2 olookin
Очень хотелось бы увидеть кусочек кода который создает эти потоки. Может напишите?
← →
olookin © (2005-01-09 16:07) [4]Честно сказать, я в потоках тоже новичок. Попробую...
← →
sniknik © (2005-01-09 16:17) [5]> Очень хотелось бы увидеть кусочек кода который создает эти потоки. Может напишите?
давно написано
x:\Program Files\Borland\Delphi7\Demos\Threads
← →
olookin © (2005-01-09 16:21) [6]Ну вот по моему это работает:
Это главный юнит:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Unit2, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
t: array [0..5] of TMyThread;
th: array [0..5] of integer;
run: boolean;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
run:=false;
for i:=0 to 5 do begin
t[i]:=TMyThread.Create(true);
t[i].Priority:=tpNormal;
th[i]:=t[i].ThreadID;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var i: integer;
begin
randomize; run:=true;
for i:=0 to 5 do t[i].Resume;
end;
end.
А это юнит с потоками:
unit Unit2;
interface
uses
Classes, sysutils, stdctrls;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure UpdateLabel;
end;
implementation
uses Unit1;
{ TMyThread }
var lind: integer;
procedure TMyThread.Execute;
var i,j,k: integer;
begin
while run do
for i:=0 to 5 do
if ThreadID=th[i] then begin
for j:=0 to Form1.ComponentCount-1 do
if Form1.Components[j].Name="Label"+inttostr(i+1) then begin
lind:=j;
Synchronize(UpdateLabel);
end;
end;
end;
procedure TMyThread.UpdateLabel;
begin
(Form1.Components[lind] as TLabel).Caption:=IntToStr(random(1000));
end;
end.
← →
Zahar (2005-01-09 16:33) [7]При компиляции:
[Warning] Unit2.pas(29): Comparing signed and unsigned types - widened both operands
При нажатии на кнопочки ничего не происходит :(
← →
Zahar (2005-01-09 16:34) [8]Кроме того пришлось закомментировать строку:
procedure Button3Click(Sender: TObject);
← →
olookin © (2005-01-09 16:48) [9]7 и 8.
Последовательность такова, сначала Button1, потом Button2. Button3 удален уже здесь, да он и не нужен. Эффект - лэйблы на форме начинают менять свои тексты.
← →
kaZaNoVa © (2005-01-09 17:07) [10]Zahar (09.01.05 15:31)
http://delphimaster.net/view/15-1105256503/
← →
Zahar (2005-01-09 17:10) [11]2 olookin
Всё равно ничего не меняется... Можешь еще раз запостить исходники?
BTW я не вижу вызов TMyThread.Execute при неажатии на кнопку...
← →
olookin © (2005-01-09 17:24) [12][11] Zahar (09.01.05 17:10)
На нажатие кнопки вызывается Resume, что как раз и запускает поток (и выполнение Execute). А метод Execute является абстрактным, так что напрямую его вызывать нельзя.
А что такое BTW?
Еще раз исходники...
Главный юнит:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Unit2, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
t: array [0..5] of TMyThread;
th: array [0..5] of integer;
run: boolean;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
создаем шесть потоков, каждый поток обслуживает свой TLabel
run:=false;
for i:=0 to 5 do begin
t[i]:=TMyThread.Create(true);
t[i].Priority:=tpNormal;
th[i]:=t[i].ThreadID; //запоминаем значения ID потока, чтобы потом по нему ориентироваться на выполнение
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var i: integer;
begin
randomize; //на TLabel будет выводиться случайное число, каждый поток генерит свое число для своей TLabel
run:=true; //флаг, по которому запускается бесконечное выполнение Execute каждого потока
for i:=0 to 5 do t[i].Resume; //запускаем все потоки, т.е. с этого момента начинает выполняться Execute в Unit2
end;
end.
Юнит с потоками:
unit Unit2;
interface
uses
Classes, sysutils, stdctrls;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure UpdateLabel;
end;
implementation
uses Unit1;
{ TMyThread }
var lind: integer;
procedure TMyThread.Execute;
var i,j,k: integer;
begin
while run do //до тех пор пока true выполняются потоки
for i:=0 to 5 do
if ThreadID=th[i] then begin //если ID текущего потока совпадает с запомненным при старте, то ищем для этого потока свою TLable по ее имени (i-му потоку соотв. TLabel с именем Label(i+1))
for j:=0 to Form1.ComponentCount-1 do
if Form1.Components[j].Name="Label"+inttostr(i+1) then begin
lind:=j; //если нашли этот поток, выполняем прорисовку его TLabel
Synchronize(UpdateLabel);
end;
end;
end;
procedure TMyThread.UpdateLabel;
begin
//прорисовка - заполнение случайным числом.
(Form1.Components[lind] as TLabel).Caption:=IntToStr(random(1000));
end;
end.
← →
olookin © (2005-01-09 17:24) [13]Да, у меня 5-я дельфи...
← →
имя (2005-01-09 17:26) [14]Удалено модератором
← →
Zahar (2005-01-09 17:32) [15]2 olookin
Странно. Ничего не происходит.
Компилирую я в Delphi7, не думаю, чтобы это как-то влияло на программу :(
BTW = By The Way = Кстати
← →
begin...end © (2005-01-09 17:35) [16]> [12] olookin © (09.01.05 17:24)
> А метод Execute является абстрактным, так что напрямую его
> вызывать нельзя.
Метод Execute является абстрактным в классе TThread.
В своих потоках Вы этот метод перекрыли, иначе смысла в этих потоках не было бы.
А вызвать его из другого модуля нельзя лишь потому, что он объявлен в секции protected.
← →
Zahar (2005-01-09 17:39) [17]Вроде удалось запустить прогу...
Но!!!
1. Программа занимет 99% процессора.
2. Цифры на Label"ах не обновляются. Обычно помогает Application.ProcessMessages. Но где его тут засунуть?
← →
Zahar (2005-01-09 17:42) [18]Решил пробему с загрузкой процессора при помощи
t[i].Priority:=tpLower
THX to olookin
← →
begin...end © (2005-01-09 17:43) [19]> [17] Zahar (09.01.05 17:39)
Вы уже ознакомились с примером из Delphi (см. [5])?
← →
Zahar (2005-01-09 17:45) [20]2 begin...end
Ознакомился, но особенность в том, что мне нужно выполнять одинаковую задачу во всех потоках (создавая нужное кол-вл потоков). Кроме того, пример несколько "наворочен".
← →
olookin © (2005-01-09 18:09) [21][16] begin...end © (09.01.05 17:35)
>>А вызвать его из другого модуля нельзя лишь потому, что он объявлен в секции protected.
Да, вы правы, согласен...
← →
sniknik © (2005-01-09 19:12) [22]> Ознакомился, но особенность в том, что мне нужно выполнять одинаковую задачу во всех потоках (создавая нужное кол-вл потоков). Кроме
> того, пример несколько "наворочен".
"обреж" лишнее, из 3-х в примере создай 1 поток, но 6-ть раз. всего делов то.
не обращайся из потока к внешним переменным и особенно свойствам форм (VCL не потоко безопасна), как в примере olookin - а.
> Решил пробему с загрузкой процессора при помощи
> t[i].Priority:=tpLower
это не решение проблемы это замыливание глаз на нее. ;о)) проблема описана немного выше.
← →
Zahar (2005-01-09 19:47) [23]2 sniknik
> это не решение проблемы это замыливание глаз на нее. ;о))
> проблема описана немного выше.
Так как всё таки решить эту проблему (я спотоками работаю первый день, поэтому извиняйте за наивные вопросы)?
← →
sniknik © (2005-01-09 20:00) [24]> Так как всё таки решить эту проблему (я спотоками работаю первый день, поэтому извиняйте за наивные вопросы)?
> не обращайся из потока к внешним переменным и особенно свойствам форм (VCL не потоко безопасна), как в примере olookin - а.
← →
Zahar (2005-01-09 20:03) [25]2 olookin
Слушай, я тут повозился с твоим кодом, но ничего дельного переделать не смог под свои нужды :(
Помоги плиз еще немножко. У тебя на всех Label-ах выводятся случайные числа. Сделай пожалуйста, чтобы каждый поток вывел свою последовательность цифр. Т.е. чтобы Label1 посчитал от 0 до 50, Label2 посчитал от 51 до 100, Label3 посчитал от 101 до 150б и т.д.
Заранее благодарен.
← →
sniknik © (2005-01-09 20:12) [26]да, под словом эту я понял > Цифры на Label"ах не обновляются.
(у тебя может на обрашении к форме может просто подвисание происходить и тогда до обновления дело не дойдет)
а вот под > Программа занимет 99% процессора.
это не проблема (сколько занимаеш столько и забирает) если хочеш давать "подышать" и другим потокам с тем же приоритетом то вставляй sleep() по ходу, вместо пустых циклов.
← →
sniknik © (2005-01-09 20:55) [27]> Помоги плиз еще немножко.
ничего если я?unit ThreadUnit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ThreadUnit2;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
ArCntThrd: array[0..5] of TCountThread;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
randomize;
ArCntThrd[0]:= TCountThread.Create(Label1, Label7, 1, 50);
ArCntThrd[1]:= TCountThread.Create(Label2, Label7, 50, 100);
ArCntThrd[2]:= TCountThread.Create(Label3, Label7, 100, 150);
ArCntThrd[3]:= TCountThread.Create(Label4, Label7, 150, 200);
ArCntThrd[4]:= TCountThread.Create(Label5, Label7, 200, 250);
ArCntThrd[5]:= TCountThread.Create(Label6, Label7, 250, 300);
end;
end.unit ThreadUnit2;
interface
uses
Classes, sysutils, stdctrls;
type
TCountThread = class(TThread)
private
fLabel, fInfo: TLabel; //это только ссылки! компоненты будут с формы
//поэтому обращение через синхронизацию обязательно!
fStart, fEnd: integer;
procedure UpdateLabel;
procedure IncCount;
procedure DecCount;
protected
procedure Execute; override;
public
constructor Create(nLabel, nInfo: TLabel; nStart, nEnd: integer);
end;
implementation
var
Count: integer = 0;
constructor TCountThread.Create(nLabel, nInfo: TLabel; nStart, nEnd: integer);
begin
fLabel:= nLabel;
fInfo:= nInfo;
fStart:= nStart;
fEnd:= nEnd;
FreeOnTerminate:= true;
inherited Create(False);
end;
procedure TCountThread.Execute;
begin
Synchronize(IncCount);
while (not Terminated) and (fStart <= fEnd) do begin
Synchronize(UpdateLabel);
fStart:= fStart + 1;
sleep(400 + random(200)); //ждем примерно пол секунды
end;
Synchronize(DecCount);
end;
procedure TCountThread.UpdateLabel;
begin
fLabel.Caption:= IntToStr(fStart);
end;
procedure TCountThread.IncCount;
begin
if Count = 0 then fInfo.Caption:= "Start Treads";
Count:= Count + 1;
end;
procedure TCountThread.DecCount;
begin
Count:= Count - 1;
if Count = 0 then fInfo.Caption:= "Finish Treads";
end;
end.
код конечно простой, но рабочий.
← →
Zahar (2005-01-09 21:08) [28]2 sniknik
COOL!!! THX!!!
Очень интересно. Буду ковыряться :)
Если что, можно обращаться с дополнительными вопросами?
← →
Alexander Panov © (2005-01-09 21:12) [29]Zahar (09.01.05 21:08) [28]
Ты статьи читал на сайте?
Zahar (09.01.05 21:08) [28]
Если что, можно обращаться с дополнительными вопросами?
Для того и форум;)
← →
sniknik © (2005-01-09 22:19) [30]> Если что, можно обращаться с дополнительными вопросами?
не конкретизируй, скорее ответят. не все же такие нещепетильные как я ;о)) на просьбу к другому отвечать.
← →
Zahar (2005-01-10 01:33) [31]Еще один вопрос:
Как следующий код выполнить в виде цикла (если например нужно реализовать 300 потоков):
ArCntThrd[0]:= TCountThread.Create(Label1, Label7, 1, 50);
ArCntThrd[1]:= TCountThread.Create(Label2, Label7, 50, 100);
ArCntThrd[2]:= TCountThread.Create(Label3, Label7, 100, 150);
ArCntThrd[3]:= TCountThread.Create(Label4, Label7, 150, 200);
ArCntThrd[4]:= TCountThread.Create(Label5, Label7, 200, 250);
ArCntThrd[5]:= TCountThread.Create(Label6, Label7, 250, 300);
← →
Zahar (2005-01-10 01:36) [32]Меня конкретно интересует как поставлять соответствующий Label (Label1, Label2, Label3 ...)
← →
sniknik © (2005-01-10 01:59) [33]300? лучше не надо. количество потоков лучше ограничивать минимумом без которого не обойтись, тормозит`с... как бы парадоксально это не звучало.
(на переключения между потоками тоже ресурсы расходуются)
т.что если можно работу выполнить в 1м потоке надо делать в одном, быстрее будет, чем то же самое в разнесенных 10ти например.
а вообше в цикл это легко впихнутьprocedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
fLabel: TLabel;
begin
randomize;
for i:= 0 to 7 do begin
fLabel:= TLabel(FindComponent("Label"+IntToStr(i+1)));
if fLabel <> nil then TCountThread.Create(fLabel, Label7, i*50, i*50+50);
end;
end;
(присвоение убрал и сам масив тоже, они лишнее сдесь, манипуляций с потоками нет уничтожаются тоже сами...) главное чтобы для 300-т лейбелов хватило ;о)).
← →
sniknik © (2005-01-10 02:02) [34](цикл до 7, 1 лишний (инфу перетрет) и один неправильный (нету такого), для примера)
← →
Zahar (2005-01-10 02:30) [35]2 sniknik
THX!!!
← →
ASoft (2005-01-10 04:33) [36]> Zahar[31] (если например нужно реализовать 300 потоков)
Цитата из книги: "Корпорация Borland не рекомендует создавать в одной програме более 16 процессов, если эта программа работает на однопроцессорном компьютере".
← →
olookin © (2005-01-10 09:03) [37][22] sniknik © (09.01.05 19:12)
>>не обращайся из потока к внешним переменным и особенно свойствам форм (VCL не потоко безопасна), как в примере olookin - а.
Не знаю, может Вы и правы, но вроде бы как при создании Thread Object в теле юнита пишут такую штуку:
{ Important: Methods and properties of objects in VCL can only be used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := "Updated in a thread";
end; }
Я все правильно понял?
← →
begin...end © (2005-01-10 09:36) [38]> [37] olookin © (10.01.05 09:03)
Вы в коде [12] обращались к свойствам формы не только в процедуре UpdateLabel, предназначенной для синхронизации, но и непосредственно в методе Execute.
← →
olookin © (2005-01-10 10:30) [39][38] begin...end © (10.01.05 09:36)
Да, действительно так. Но мне казалось, что собственно в "Methods and properties of objects in VCL can only be used... " имелось в виду НАЗНАЧЕНИЕ свойства, а не его чтение. Значит, я снова был неправ.
← →
KSergey © (2005-01-10 11:11) [40]> Zahar (09.01.05 15:31)
> Есть текстовый файл в котором N-строк с числами (для примера
> возьмем 300).
Хотелось бы по исходной задаче немного написать.
Если это просто учебная проба - то ладно.
А вообще имейте в виду, что один поток (например - основной) в итоге обработает вась файл быстрее, нежели N параллельных, обрабатывающих разные куски файла.
Страницы: 1 2 вся ветка
Форум: "Основная";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.036 c