Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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 параллельных, обрабатывающих разные куски файла.


 
Alexander Panov ©   (2005-01-10 11:14) [41]

KSergey ©   (10.01.05 11:11) [40]
А вообще имейте в виду, что один поток (например - основной) в итоге обработает вась файл быстрее, нежели N параллельных, обрабатывающих разные куски файла.


Если система однопроцессорная. Но и при этом условии тоже не факт. Зависит от того, какая обработка данных проводится , от контроллра дисков, от объема RAM и пр...


 
TUser ©   (2005-01-10 11:29) [42]

ИМХО, использование нескольких потоков для данной задачи нужно непонятно зачем - оно приведет лишь к замедлению работы с файлом.


 
KSergey ©   (2005-01-10 12:57) [43]

> [41] Alexander Panov ©   (10.01.05 11:14)
> KSergey ©   (10.01.05 11:11) [40]
> Если система однопроцессорная. Но и при этом условии тоже
> не факт.

ПРи каком "этом"? При многопроцессорности или однопроцессорности?


 
sniknik ©   (2005-01-10 14:37) [44]

> ПРи каком "этом"? При многопроцессорности или однопроцессорности?
так понимаю смотря что "тормозит", если расчеты то вряд ли разнесение по потокам даст прирост скорости...
но вот если поток в основном занимается ожиданием события какого нибудь то несколько вполне мугут сработать быстрее (пример FlashGet при закачке в несколько потоков). и неважно сколько процессоров. ;)


 
sniknik ©   (2005-01-10 14:47) [45]

olookin ©   (10.01.05 10:30) [39]
> " имелось в виду НАЗНАЧЕНИЕ свойства, а не его чтение.

чтение тоже "чревато" последствиями, ты читаеш другой поток пишет в итоке ты получил неопределенное значение, часть от старого часть нового значения. это хорошо?
ну и потом даже чтение свойства (property) может вызывать довольно сложные процедуры (и на запись тоже) смотря как оно реализовано, а если (например) гдето подсчет вхождений в свойство идет и выход только с парным (вход + выход -, и выйдет только если 0), ты туда влез незапланировано... и в итоге "клинч" ни ты ни основной поток работать не можете, зависли в обработке проперти. (только как пример!)


 
olookin ©   (2005-01-10 15:30) [46]

[45] sniknik ©   (10.01.05 14:47)

Согласен, но в отношении моего кода - могу я беспрепятственно читать "имя" компонента, или это тоже чревато?


 
sniknik ©   (2005-01-10 17:04) [47]

olookin ©   (10.01.05 15:30) [46]
нельзя! ни в коем случае (даже если на первый взгяд кажется что можно, и не с чем не пересекается не изменяется и .т.д.)
всегда есть вероятность (и очень очень большая) что гдето чтото не учел, мало ли событий в которых туда же обращение и блокировки ставятся. (onPaint например, ты учитывал? в нем тоже должно быть обращение к компонентам формы) а если вдруг исключение будет? там по ексепту VCL-ная форма с мессажем подымается, в потоке  это недопустимо.



Страницы: 1 2 вся ветка

Форум: "Основная";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.6 MB
Время: 0.036 c
14-1104461424
Думкин
2004-12-31 05:50
2005.01.23
С днем рождения! 31 декабря


1-1104406951
den303
2004-12-30 14:42
2005.01.23
TButton+Glyph


3-1103614472
Mishenka
2004-12-21 10:34
2005.01.23
Может ли таблица быть связана сама с собой?


1-1105268786
olookin
2005-01-09 14:06
2005.01.23
mrYes: Неизвестный идентификатор


8-1097515235
tox
2004-10-11 21:20
2005.01.23
Плейлисты





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский