Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.05.2012, 16:00   #1
Belinos
Новичок
Джуниор
 
Регистрация: 26.05.2012
Сообщений: 2
По умолчанию Копирование файлов(тройная буферизация, потоки)

Задание выглядит так:
Разработать программу, реализующую копирование файлов при помощи тройной буферизации. Программа должна использовать потоки. Первый поток считывает блок данных из указанного файла. Второй поток записывает этот блок данных в файл. Буферизацию реализовать при помощи 2-х массивов состоящих из трех элементов. Каждый элемент - это буфер. Первый массив отвечает за чтение из файла, а второй за запись. Первый поток получает имя файла, берет пустой элемент из первого массива, записывает в него блок данных и передает второму массиву этот блок данных. При этом буфер, в который считали блок данных обнуляется. Второй поток, видя, что во втором массиве есть полный буфер, записывает этот буфер в файл и обнуляет его. При этом в первом массиве выделяется новый буфер. И так пока весь файл не будет скопирован. Реализовать на языке Паскаль, в среде Delphi.

Долго тыкаюсь уже, ничего не выходит. Получилось сделать только однопоточное копирование с одним буфером.
Помогите, пожалуйста!

Последний раз редактировалось Belinos; 26.05.2012 в 17:02.
Belinos вне форума Ответить с цитированием
Старый 26.05.2012, 21:26   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

походу, задание давал человек, который не имеет даже самого отдалённого понимания о межпоточной синхронизации данных.

Слегка непривычное использование семафоров, а так ничё сложного:

Код:
program
  tripleBuf;

{$APPTYPE CONSOLE}

uses
  Windows;

const
  c_maxBuf	 = 3;

type
  buf = array[word] of byte;
  //
  bufRec = record
    data: buf;
    sz: cardinal;
  end;

var
  writeBuf: array[0..c_maxBuf - 1] of bufRec;
  //
  sr, sw: tHandle;	// read/write semaphores
  doneEv: tHandle;	// read job done

// --  --
function readThread(lpParameter: pointer): DWORD; stdcall;
var
  s: tHandle;
  iw, br: cardinal;
  wc: DWORD;
  readBuf: buf;
begin
  s := pHandle(lpParameter)^;
  iw := 0;
  //
  while (ReadFile(s, readBuf, sizeof(readBuf), br, nil)) do begin
    //
    if (0 < br) then begin
      //
      // do we have at least one write buffer?
      wc := WaitForSingleObject(sw, INFINITE);
      if (WAIT_OBJECT_0 = wc) then begin
	//
	move(readBuf, writeBuf[iw].data, br);
	writeBuf[iw].sz := br;
	//
        // tell writting thread we have some data passed to it
	ReleaseSemaphore(sr, 1, nil);
	//
	inc(iw);
	if (iw >= c_maxBuf) then
	  iw := 0;
      end
      else
	break;	// unable to wait for write buffer
    end
    else
      break;	// EOF
  end;
  //
  SetEvent(doneEv); // done with reading
  result := 0;
end;

// --  --
function writeThread(lpParameter: pointer): DWORD; stdcall;
var
  d: tHandle;
  iw, bw: cardinal;
  wc: DWORD;
begin
  d := pHandle(lpParameter)^;
  iw := 0;
  //
  repeat
    //
    // do we have at least one buffer to write?
    wc := WaitForSingleObject(sr, 50);
    if (WAIT_OBJECT_0 = wc) then begin
      //
      WriteFile(d, writeBuf[iw].data, writeBuf[iw].sz, bw, nil);
      //
      // tell reading thread we are done with buffer
      ReleaseSemaphore(sw, 1, nil);
      //
      inc(iw);
      if (iw >= c_maxBuf) then
	iw := 0;
    end
    else
      if (WAIT_OBJECT_0 = WaitForSingleObject(doneEv, 1)) then
	break;	// EOF
    //
  until (false);
  //
  result := 0;
end;

// --  --
procedure copyFile(const src, dst: string);
var
  s, d, rt, wt: tHandle;
  tid: cardinal;
begin
  s := CreateFile(pChar(src), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if (INVALID_HANDLE_VALUE <> s) then try
    //
    d := CreateFile(pChar(dst), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, FILE_ATTRIBUTE_NORMAL);
    if (INVALID_HANDLE_VALUE <> d) then try
      //
      sr := CreateSemaphore(nil, 0       , c_maxBuf, nil); // no buffers from read thread yet
      sw := CreateSemaphore(nil, c_maxBuf, c_maxBuf, nil); // all write thread buffers are ready
      doneEv := CreateEvent(nil, true, false, nil);
      //
      // start reading
      rt := CreateThread(nil, 0, @readThread, @s, 0, tid);
      if (0 <> rt) then try
	//
        // and writting
	wt := CreateThread(nil, 0, @writeThread, @d, 0, tid);
	if (0 <> wt) then try
	  //
	finally
	  WaitForSingleObject(wt, INFINITE);
	  CloseHandle(wt);
	end
	else
	  writeln('Could not create read thread.');
      finally
	WaitForSingleObject(rt, INFINITE);
	CloseHandle(rt);
      end
      else
	writeln('Could not create read thread.');
    finally
      CloseHandle(d);
      //
      CloseHandle(sr);
      CloseHandle(sw);
      CloseHandle(doneEv);
    end
    else
      writeln('Could not create destination file.');
  finally
    CloseHandle(s);
  end
  else
    writeln('Could not open source file.');
end;

// -- main --

begin
  if (paramCount < 2) then
    writeln('usage: <source file> <dest file>')
  else
    copyFile(paramStr(1), paramStr(2));
end.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 26.05.2012, 22:11   #3
s-andriano
Старожил
 
Аватар для s-andriano
 
Регистрация: 08.04.2012
Сообщений: 3,229
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
походу, задание давал человек, который не имеет даже самого отдалённого понимания о межпоточной синхронизации данных.
Да уж.
Боюсь, предложенный им способ реализации проигрывает простому однопоточному решению по всем без исключения параметрам:
- по сложности реализации,
- по надежности,
- по ресурсоемкости,
- по скорости работы.

Кстати, по условию с файлами должны работать (в частности, открывать их) дополнительные потоки, а не основной.

Последний раз редактировалось s-andriano; 26.05.2012 в 22:15.
s-andriano вне форума Ответить с цитированием
Старый 26.05.2012, 22:23   #4
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> проигрывает простому однопоточному решению по всем без исключения параметрам:

в общем да, потоки тут не пришей собаке хвост. Всё это делается через OVERLAPPED чтение/запись в несколько строк, и пусть система сама оптимизирует файловые операции, это у неё получится явно лучше, чем у нас.


> по условию с файлами должны работать (в частности, открывать их) дополнительные потоки, а не основной.

не заметил, ну, значит, надо передавать в поток не хэндл, а указатель на имя файла.

Для себя я освежил в памяти работу с семафорами, а топикастер пусть уже сам разбирается с кодом и преподавателем )
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 29.05.2012, 17:20   #5
Belinos
Новичок
Джуниор
 
Регистрация: 26.05.2012
Сообщений: 2
По умолчанию

Спасибо большое! Покажу преподавателю =)
Belinos вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Буферизация файлов PUSHkiN C# (си шарп) 3 24.04.2011 15:55
Потоки, передача файлов по сети SeЯgey Работа с сетью в Delphi 3 02.04.2011 23:51
копирование строки из файла используя потоки tim91 Общие вопросы Delphi 11 22.02.2011 19:03
Копирование файлов ARXangel Общие вопросы Delphi 5 30.10.2008 12:29