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

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

TThread копирование файла в 2-х потоках [D7]


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

PacMan ©   (2012-05-01 20:31:00) 

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

листинг:
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, unit2, StdCtrls, SyncObjs, Gauges;

type
 TForm1 = class(TForm)
   Label1: TLabel;
   Label2: TLabel;
   Button1: TButton;
   Edit1: TEdit;
   Edit2: TEdit;
   OpenDialog1: TOpenDialog;
   SaveDialog1: TSaveDialog;
   Label3: TLabel;
   Gauge1: TGauge;
   procedure Button1Click(Sender: TObject);
   procedure Edit1Click(Sender: TObject);
   procedure Edit2Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 CriticalSection:=TCriticalSection.Create;
 stream1.Create(false);
 stream2.Create(false);
end;

procedure TForm1.Edit1Click(Sender: TObject);
begin
 if OpenDialog1.Execute then
   Edit1.Text := OpenDialog1.FileName;
end;

procedure TForm1.Edit2Click(Sender: TObject);
begin
 if SaveDialog1.Execute then
   Edit2.Text := SaveDialog1.FileName;
end;

end.

unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, SyncObjs;

type
 stream1 = class(TThread)

 protected

 public
   Procedure Podgot;
   Procedure ZabivBuf;
   Procedure Zakon;
   procedure Execute; override;
 end;

 stream2 = class(TThread)

 protected

 public
   procedure Execute; override;
   procedure FWrite;
 end;

 var
 f1, f2: File; // первый и второй файл
 buf1: array [1..8192] of Char; //буфер 1
 buf2: array [1..8192] of Char; //буфер 2
 sizefile, sizeread: Int64; //размер файла и размер прочитанного
 colRead, colWrite : Integer; //прочитано и записано
 fOtkuda, fKuda : String; //адреса и имена файлов
 CriticalSection: TCriticalSection;
 flag: Boolean;

 implementation
 uses unit1;

procedure stream1.Execute;
begin
 Podgot;
 while colRead = colWrite do
 begin
   if flag=false then   //если буфер 2 уже пустой
   begin
     CriticalSection.Enter;
     ZabivBuf;

   end;
 end;
 Zakon;
end;

procedure stream2.Execute;
begin
 while colRead = colWrite do
 begin
   if flag=True then   //если буфер 2 уже пустой
   begin
     CriticalSection.Enter;
     Fwrite;
   end;
 end;
end;

Procedure stream1.Podgot;       // подготовка
var i:integer;
begin
 {i-} //даем компилятору директиву, чтобы не отслеживал ошибки ввода-вывода:
 if (Form1.Edit1.Text='') or (Form1.Edit2.Text='') then   //проверяем, указаны ли файлы. если нет - выходим
 begin
   ShowMessage('Вы не указали данные для копирования');
   Exit;
 end;
 //Try
   AssignFile(f1, Form1.Edit1.Text);  //связываем файловые переменные:
   AssignFile(f2, Form1.Edit2.Text);
   Reset(F1, 1);  //связываем файловые переменные:
   sizefile := FileSize(f1); //определяем его размер в переменную:
   Form1.Label3.Caption := 'Размер файла: '+IntToStr(Round(sizefile / 8192)) + ' Кб.';     //отображаем размер файла в килобайтах:
   Rewrite(f2, 1);  //создаем или перезаписываем второй файл:
   colRead := 0;    //делаем, пока не достигнут конец исходного файла
   colWrite := 0;
   sizeread := 0;
   Screen.Cursor := crHourGlass; //песочные часы
   {i+}
end;

Procedure Stream1.ZabivBuf;
var
   i:integer;    //while colRead = colWrite do
begin
 {i-}
 BlockRead(f1, Buf1, SizeOf(Buf1), colRead);
 //if colRead = 0 then break;

   for I := 1 to 8192 do
     Buf2[i]:=Buf1[i];  //Буфер1 в Буфер2

 Form1.Gauge1.Progress := Round(100*sizeread/sizefile);
 Flag:=True;
 CriticalSection.Leave;
 {i+}
end;

Procedure Stream1.Zakon;
begin
 {i-}
   Screen.Cursor := crDefault; //обычный вид курсора
 //Finally
   CloseFile(f1);
   CloseFile(f2);
 //end; //try
 fOtkuda := Form1.Edit1.Text;  //исправляем дату
 fKuda := Form1.Edit2.Text;
 if IOResult <> 0 then
   Application.MessageBox('Ошибка при копировании файла!', 'Внимание!!!',
     MB_OK+MB_ICONERROR)
 else ShowMessage('Копирование  завершено успешно');
 //включаем обработчик компилятором ошибок
 {i+}
End;

procedure stream2.FWrite;
var
   i: Integer;
begin
   BlockWrite(f2, Buf2, colRead, colWrite);
   sizeread := sizeread + colRead;
   Flag:=False;
   CriticalSection.Leave;

end;

end.


sniknik   (2012-05-01 21:27:00) [41]

> как 1 заставить ждать, пока не выполнится что-либо во-2м...
уже используется - CriticalSection.Enter; во втором заставит первый ждать, не скажу насчет правильности, логики его использования у тебя, но это вот оно.

и кстати у тебя куча всего чего нельзя в потоках... типа прямого обращения к vcl.


PacMan   (2012-05-01 20:52:00) [42]

меня это не смущает, т.к. по заданию мне нужно копировать файл в 2-х потоках, и препод ничего не может мне подсказать по этому поводу.
Если у кого-то есть "знание" как сделать хотя бы это, буду благодарен.
Если кто-то может показать как сделать оптимальнее, также буду благодарен.


sniknik   (2012-05-01 20:44:00) [43]

> как 1 заставить ждать, пока не выполнится что-либо во-2м...
а то что по сути это станет одним потоком, просто с разнесенным кодом/логикой на два тебя не смущает?

получается типа, "хочу нести воду в 2х ведрах, но так чтобы пол пути в одном, пол в другом. как на полпути воду в ведрах местами поменять? емкостей то больше нет".


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

Наверх

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