Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.01.23;
Скачать: CL | DM;

Вниз

помогите с разобраться с потоками   Найти похожие ветки 

 
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://predskazanie-wunschpunsch.ru/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;
Скачать: CL | DM;

Наверх




Память: 0.59 MB
Время: 0.035 c
14-1104810577
DelphiN!
2005-01-04 06:49
2005.01.23
Где скачать все выпуски RSDN Magazine ?


1-1105394964
Kick
2005-01-11 01:09
2005.01.23
У фрейма нет события OnCreate, как же мне инициализировать переме


1-1105616091
Zilog
2005-01-13 14:34
2005.01.23
группы SpeedButton ов


3-1103537492
IgorV
2004-12-20 13:11
2005.01.23
QReport, вложенная группировка


3-1103550189
/glokk
2004-12-20 16:43
2005.01.23
FIBPlus (backup/restore)