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

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

помогите с разобраться с потоками [D7]


Страницы:   1 2 3

Zahar ©   (2005-01-09 15:31:00) 

Помогите плиз разобраться с потоками. Нашел кучу информации где разные потоки выполняют разные функции, а мне нужно чтобы все потоки выполняли одну и ту же операцию.

Задача дла примера:

Есть текстовый файл в котором 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 и записать в конечный файл.

Т.е. функция для потока будет одна, но обрабатывать в каждом потоке она будет разные последовательности данных.

Помогие очень разобраться с этой задачей. В потоках я полный новичек.

Заранее благодарен за любую помощь.


sniknik   (2005-01-09 20:55:00) [21]

> Помоги плиз еще немножко.
ничего если я?

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.


код конечно простой, но рабочий.


sniknik   (2005-01-09 20:12:00) [22]

да, под словом этуя понял > Цифры на Label'ах не обновляются.
(у тебя может на обрашении к форме может просто подвисание происходить и тогда до обновления дело не дойдет)

а вот под > Программа занимет 99% процессора.
это не проблема (сколько занимаеш столько и забирает) если хочеш давать "подышать" и другим потокам с тем же приоритетом то вставляй sleep() по ходу, вместо пустых циклов.


Zahar   (2005-01-09 20:03:00) [23]

2 olookin

Слушай, я тут повозился с твоим кодом, но ничего дельного переделать не смог под свои нужды :(

Помоги плиз еще немножко. У тебя на всех Label-ах выводятся случайные числа. Сделай пожалуйста, чтобы каждый поток вывел свою последовательность цифр. Т.е. чтобы Label1 посчитал от 0 до 50, Label2 посчитал от 51 до 100, Label3 посчитал от 101 до 150б и т.д.

Заранее благодарен.


sniknik   (2005-01-09 20:00:00) [24]

> Так как всё таки решить эту проблему (я спотоками работаю первый день, поэтому извиняйте за наивные вопросы)?
> не обращайся из потока к внешним переменным и особенно свойствам форм (VCL не потоко безопасна), как в примере olookin - а.


Zahar   (2005-01-09 19:47:00) [25]

2 sniknik
> это не решение проблемы это замыливание глаз на нее. ;о))
> проблема описана немного выше.


Так как всё таки решить эту проблему (я спотоками работаю первый день, поэтому извиняйте за наивные вопросы)?


sniknik   (2005-01-09 19:12:00) [26]

> Ознакомился, но особенность в том, что мне нужно выполнять одинаковую задачу во всех потоках (создавая нужное кол-вл потоков). Кроме
> того, пример несколько "наворочен".
"обреж" лишнее, из 3-х в примере создай 1 поток, но 6-ть раз. всего делов то.

не обращайся из потока к внешним переменным и особенно свойствам форм (VCL не потоко безопасна), как в примере olookin - а.

> Решил пробему с загрузкой процессора при помощи
> t[i].Priority:=tpLower
это не решение проблемы это замыливание глаз на нее. ;о)) проблема описана немного выше.


olookin   (2005-01-09 18:09:00) [27]

[16] begin...end ©   (09.01.05 17:35)
>>А вызвать его из другого модуля нельзя лишь потому, что он объявлен в секции protected.

Да, вы правы, согласен...


Zahar   (2005-01-09 17:45:00) [28]

2 begin...end

Ознакомился, но особенность в том, что мне нужно выполнять одинаковую задачу во всех потоках (создавая нужное кол-вл потоков). Кроме того, пример несколько "наворочен".


begin...end   (2005-01-09 17:43:00) [29]

> [17] Zahar   (09.01.05 17:39)

Вы уже ознакомились с примером из Delphi (см. [5])?


Zahar   (2005-01-09 17:42:00) [30]

Решил пробему с загрузкой процессора при помощи

t[i].Priority:=tpLower


THX to olookin


Zahar   (2005-01-09 17:39:00) [31]

Вроде удалось запустить прогу...

Но!!!

1. Программа занимет 99% процессора.
2. Цифры на Label'ах не обновляются. Обычно помогает Application.ProcessMessages. Но где его тут засунуть?


begin...end   (2005-01-09 17:35:00) [32]

> [12] olookin ©   (09.01.05 17:24)

> А метод Execute является абстрактным, так что напрямую его
> вызывать нельзя.

Метод Execute является абстрактным в классе TThread.
В своих потоках Вы этот метод перекрыли, иначе смысла в этих потоках не было бы.
А вызвать его из другого модуля нельзя лишь потому, что он объявлен в секции protected.


Zahar   (2005-01-09 17:32:00) [33]

2 olookin

Странно. Ничего не происходит.
Компилирую я в Delphi7, не думаю, чтобы это как-то влияло на программу :(

BTW = By The Way = Кстати


  (2005-01-09 17:26:00) [34]

Удалено модератором


olookin   (2005-01-09 17:24:00) [35]

Да, у меня 5-я дельфи...


olookin   (2005-01-09 17:24:00) [36]

[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.


Zahar   (2005-01-09 17:10:00) [37]

2 olookin

Всё равно ничего не меняется... Можешь еще раз запостить исходники?

BTW я не вижу вызов TMyThread.Execute при неажатии на кнопку...


kaZaNoVa   (2005-01-09 17:07:00) [38]

Zahar   (09.01.05 15:31)
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1105256503&n=3


olookin   (2005-01-09 16:48:00) [39]

7 и 8.

Последовательность такова, сначала Button1, потом Button2. Button3 удален уже здесь, да он и не нужен. Эффект - лэйблы на форме начинают менять свои тексты.


Zahar   (2005-01-09 16:34:00) [40]

Кроме того пришлось закомментировать строку:

procedure Button3Click(Sender: TObject);


Страницы:   1 2 3

Наверх

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