<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=348570&amp;view=findpost&amp;p=3056162</guid>
        <pubDate>Thu, 05 Jan 2012 23:17:43 +0000</pubDate>
        <title>Обёртка IOCP с примерами</title>
        <link>https://forum.sources.ru/index.php?showtopic=348570&amp;view=findpost&amp;p=3056162</link>
        <description><![CDATA[Демо: Захотел поразмять мозги в новогодние выходные.<br>
Поставил себе задачу:<br>
<br>
1. Написать некий класс-обёртку для использования порта завершения ввода/вывода (TIOCP)<br>
2. Написать класс для испльзования готового TIOCP. (TJob).<br>
<br>
То, что получилось, выкладываю с примерами - может кому пригодится.<br>
Не шедевр, конечно, но работает.<br>
Критика приветствуется.<br>
<br>
Логика использования:<br>
<br>
1. Создаётся экземпляр класса TIOCP вместе с пулом потоков<br>
2. Создаётся наследник класса TJob, в котором <br>
- В перекрытом конструкторе открываются нужные устройства (файлы, сокеты, пайпы и пр.)<br>
- В реализованном абстрактном методе TJob.ExecProc реализуется логика обработки в пуле потоков<br>
- Основной поток получает данные о выполнении задания и может реагировать в зависимости от ситуации<br>
<br>
Пример пока один. Сейчас пишу второй - сервер перенаправления портов TCP, выложу чуть позже.<br>
<br>
Модуль с классами<br>
<div class="tag-spoiler spoiler closed"><div class="spoiler_header" onclick="openCloseParent(this)">Скрытый текст</div><div class="body"><br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">(*-------------------------------------------------</div><div class="code_line">Обёртка для работы с портом завершения ввода/вывода</div><div class="code_line">2012, Демо</div><div class="code_line">sources.ru</div><div class="code_line">-------------------------------------------------*)</div><div class="code_line">unit uIOCP;</div><div class="code_line">&nbsp;</div><div class="code_line">interface</div><div class="code_line">&nbsp;</div><div class="code_line">uses</div><div class="code_line">&nbsp;&nbsp;Windows,</div><div class="code_line">&nbsp;&nbsp;SysUtils,</div><div class="code_line">&nbsp;&nbsp;Messages,</div><div class="code_line">&nbsp;&nbsp;Classes,</div><div class="code_line">&nbsp;&nbsp;SyncObjs;</div><div class="code_line">&nbsp;</div><div class="code_line">type</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;TIOCP=class;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;</div><div class="code_line">//Состояния заданий</div><div class="code_line">&nbsp;&nbsp;TJobState=(jsNone, jsProcess, jsError, jsCompleted);</div><div class="code_line">&nbsp;</div><div class="code_line">// &nbsp;Экземпляры этого класса используются</div><div class="code_line">//для выполнения заданий с использованием IOCP</div><div class="code_line">&nbsp;&nbsp;TJob=class</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;FIOCP: TIOCP; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Ссылка на класс с IOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp;FOV: POverlapped; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //OVERLAPPED-структура, используемая IOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp;FState: TJobState;</div><div class="code_line">&nbsp;&nbsp; &nbsp;FNumBytes: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Количество байт, прочитанных/записанных</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//последней операцией</div><div class="code_line">&nbsp;&nbsp; &nbsp;FCS: TCriticalSection; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Критическая секция для использования в TJob</div><div class="code_line">&nbsp;&nbsp; &nbsp;FUD: Pointer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Пользовательские данные</div><div class="code_line">&nbsp;&nbsp; &nbsp;FErrorCode: Integer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Последняя ошибка</div><div class="code_line">&nbsp;&nbsp; &nbsp;FCodeOp: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Текущий код операции</div><div class="code_line">&nbsp;&nbsp; &nbsp;function GetPort: THandle;</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create(IOCP: TIOCP);</div><div class="code_line">&nbsp;&nbsp; &nbsp;destructor Destroy; override;</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure ExecProc; virtual; abstract; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Процедура, выполняемая</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//в потоках IOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp;function Complete(Code: Cardinal): Boolean; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Вызывает немедленную обработку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//в потоке</div><div class="code_line">&nbsp;&nbsp; &nbsp;function Associate(DeviceHandle: THandle): THandle; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Добавление устройства в таблицу IOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Вызывает метод из TIOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp;function CheckIOCP: Boolean; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Проверка, жив ли ещё IOCP</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property IOPort: THandle read GetPort;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property State: TJobState read FState write FState;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property NumBytes: Cardinal read FNumBytes;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property CS: TCriticalSection read FCS;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property ErrorCode: Integer read FErrorCode write FErrorCode;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property UserData: Pointer read FUD write FUD;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property OV: POVERLAPPED read FOV;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property CodeOp: Cardinal Read FCodeOp Write FCodeOp;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Класс порта завершения</div><div class="code_line">&nbsp;&nbsp;TIOCP=class</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;FIOCP: THandle; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Порт IOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp;FThreadList: TList; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Список потоков, которые обрабатывают порт IOCP</div><div class="code_line">&nbsp;&nbsp; &nbsp;FWorkThreadsCount: Integer; &nbsp; &nbsp; &nbsp; //Количество рабочих потоков. Обычно равно (кол-во процессоров)</div><div class="code_line">&nbsp;&nbsp; &nbsp;FMaxThreadsCount: Integer; &nbsp; &nbsp; &nbsp; &nbsp;//Общееколичество потоков. Обычно ранво (кол-во процессоров)*2</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create(ThreadsCount: Cardinal=0);</div><div class="code_line">&nbsp;&nbsp; &nbsp;destructor Destroy; override;</div><div class="code_line">&nbsp;&nbsp; &nbsp;function Associate(DeviceHandle: THandle; CompKey: Cardinal): THandle; //Добавление устройства в таблицу IOCP</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property IOPort: THandle read FIOCP;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property WorkThreadsCount: Integer read FWorkThreadsCount;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Потоки, связанные с IOCP</div><div class="code_line">&nbsp;&nbsp;TWorkThread=class(TThread)</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;FIOCP: TIOCP;</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create(IOCP: TIOCP);</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure Execute; override;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">implementation</div><div class="code_line">&nbsp;</div><div class="code_line">{ TIOCP }</div><div class="code_line">&nbsp;</div><div class="code_line">function TIOCP.Associate(DeviceHandle: THandle;</div><div class="code_line">&nbsp;&nbsp;CompKey: Cardinal): THandle;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := CreateIoCompletionPort(DeviceHandle,FIOCP,CompKey,0);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TIOCP.Create(ThreadsCount: Cardinal=0);</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;i: Integer;</div><div class="code_line">&nbsp;&nbsp;SI: TSystemInfo;</div><div class="code_line">begin</div><div class="code_line">//Количество потоков по-умолчанию = Кол-во процессоров*2</div><div class="code_line">&nbsp;&nbsp;if ThreadsCount=0 then</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetSystemInfo(SI);</div><div class="code_line">&nbsp;&nbsp; &nbsp;FWorkThreadsCount := SI.dwNumberOfProcessors;</div><div class="code_line">&nbsp;&nbsp; &nbsp;FMaxThreadsCount := FWorkThreadsCount*2;</div><div class="code_line">&nbsp;&nbsp;end</div><div class="code_line">&nbsp;&nbsp;else</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;FWorkThreadsCount := ThreadsCount;</div><div class="code_line">&nbsp;&nbsp; &nbsp;FMaxThreadsCount := FWorkThreadsCount;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Сооздаём порт заввершения в/в</div><div class="code_line">&nbsp;&nbsp;FIOCP := CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,FWorkThreadsCount);</div><div class="code_line">&nbsp;&nbsp;if FIOCP=0 then raise Exception.Create(SysErrorMessage(GetLastError));</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;FThreadList := TList.Create;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;for i := 1 to FMaxThreadsCount do</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;FThreadList.Add(TWorkThread.Create(Self));</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">destructor TIOCP.Destroy;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;i: Integer;</div><div class="code_line">begin</div><div class="code_line">//Посылаем всем потокам команду закончить работу (CompKey=0)</div><div class="code_line">&nbsp;&nbsp;for i := 0 to FThreadList.Count-1 do PostQueuedCompletionStatus(FIOCP,0,0,nil);</div><div class="code_line">//Ожидаем завершения всех потоков</div><div class="code_line">&nbsp;&nbsp;for i := 0 to FThreadList.Count-1 do</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;with TWorkThread(FThreadList[i]) do</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;WaitFor;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Free;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;CloseHandle(FIOCP);</div><div class="code_line">&nbsp;&nbsp;FThreadList.Free;</div><div class="code_line">&nbsp;&nbsp;inherited Destroy;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;</div><div class="code_line">{ TWorkThread }</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TWorkThread.Create(IOCP: TIOCP);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;inherited Create(True);</div><div class="code_line">&nbsp;&nbsp;FIOCP := IOCP;</div><div class="code_line">&nbsp;&nbsp;FreeOnTerminate := False;</div><div class="code_line">&nbsp;&nbsp;Resume;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TWorkThread.Execute;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;NumBytes: Cardinal;</div><div class="code_line">&nbsp;&nbsp;CompKey: Cardinal;</div><div class="code_line">&nbsp;&nbsp;ov: POVERLAPPED;</div><div class="code_line">&nbsp;&nbsp;J: TJob;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;while not Terminated do</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;if GetQueuedCompletionStatus(FIOCP.IOPort,NumBytes,CompKey,ov,INFINITE) then</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;if CompKey=0 then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Terminate;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Continue;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;end;</div><div class="code_line">//Для проверки того, что IOCP жив посылаем в порт запрос с CompKey=1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;if Compkey=1 then Continue;</div><div class="code_line">//Полученный CompKey и есть наш TJob</div><div class="code_line">&nbsp;&nbsp; &nbsp;J := Pointer(CompKey);</div><div class="code_line">&nbsp;&nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;J.FNumBytes := NumBytes;</div><div class="code_line">//Выполняем обработку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;J.ExecProc;</div><div class="code_line">&nbsp;&nbsp; &nbsp;except</div><div class="code_line">//Возвращаем признак ошибки</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;J.FState := jsError;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end</div><div class="code_line">&nbsp;&nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;if CompKey&#60;&#62;0 then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;begin</div><div class="code_line">//Возвращаем признак ошибки</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;J := Pointer(CompKey);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;J.FErrorCode := GetLastError;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;J.FState := jsError;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">{ TJob }</div><div class="code_line">&nbsp;</div><div class="code_line">function TJob.Associate(DeviceHandle: THandle): THandle;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := FIOCP.Associate(DeviceHandle,Cardinal(Self));</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Для проверки того, что IOCP жив посылаем в порт запрос с CompKey=1</div><div class="code_line">function TJob.CheckIOCP: Boolean;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;Err: Integer;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := True;</div><div class="code_line">&nbsp;&nbsp;if not PostQueuedCompletionStatus(FIOCP.FIOCP,0,1,nil) then</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;Err := GetLastError;</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Err=ERROR_INVALID_HANDLE then Result := False;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TJob.Complete(Code: Cardinal): Boolean;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;CodeOp := Code;</div><div class="code_line">&nbsp;&nbsp;Result := PostQueuedCompletionStatus(FIOCP.IOPort,0,Cardinal(Self),POVERLAPPED(FOV));</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TJob.Create(IOCP: TIOCP);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FIOCP := IOCP;</div><div class="code_line">&nbsp;&nbsp;FState := jsNone;</div><div class="code_line">&nbsp;&nbsp;FCS := TCriticalSection.Create;</div><div class="code_line">&nbsp;&nbsp;New(FOV);</div><div class="code_line">&nbsp;&nbsp;FOV^.Internal := 0;</div><div class="code_line">&nbsp;&nbsp;FOV^.InternalHigh :=0;</div><div class="code_line">&nbsp;&nbsp;FOV^.Offset := 0;</div><div class="code_line">&nbsp;&nbsp;FOV^.OffsetHigh := 0;</div><div class="code_line">//При необходимости выполнения операции с устройством без передачи IOCP</div><div class="code_line">//перед выполнением операции устанавливаем младший бит hEvent в 1:</div><div class="code_line">// &nbsp; &nbsp; FOV^.hEvent := FOV^.hEvent or 1;</div><div class="code_line">&nbsp;&nbsp;FOV^.hEvent := CreateEvent(nil,True,False,nil);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">destructor TJob.Destroy;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;CloseHandle(FOV^.hEvent);</div><div class="code_line">&nbsp;&nbsp;Dispose(FOV);</div><div class="code_line">&nbsp;&nbsp;FCS.Free;</div><div class="code_line">&nbsp;&nbsp;inherited;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TJob.GetPort: THandle;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := FIOCP.FIOCP;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">end.</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
</div></div><br>
<br>
<br>
Пример с копированием файлов:<br>
<br>
<div class="tag-spoiler spoiler closed"><div class="spoiler_header" onclick="openCloseParent(this)">Скрытый текст</div><div class="body"><br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">unit Unit1;</div><div class="code_line">&nbsp;</div><div class="code_line">interface</div><div class="code_line">&nbsp;</div><div class="code_line">uses</div><div class="code_line">&nbsp;&nbsp;Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,</div><div class="code_line">&nbsp;&nbsp;Dialogs, StdCtrls, uIOCP, ExtCtrls;</div><div class="code_line">&nbsp;</div><div class="code_line">const</div><div class="code_line">&nbsp;</div><div class="code_line">//Коды операций</div><div class="code_line">&nbsp;&nbsp;coRead &nbsp; &nbsp;= 1;</div><div class="code_line">&nbsp;&nbsp;coWrite &nbsp; = 2;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;BufSize=64*1024; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Размер буфера чтения/записи</div><div class="code_line">&nbsp;</div><div class="code_line">type</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;TForm1 = class(TForm)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Button1: TButton;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Button2: TButton;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Label1: TLabel;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Timer1: TTimer;</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure Button1Click(Sender: TObject);</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure Button2Click(Sender: TObject);</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure Timer1Timer(Sender: TObject);</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;{ Private declarations }</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;{ Public declarations }</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Наследник TJob</div><div class="code_line">//В этом классе реализована вся логика по копированию файла</div><div class="code_line">&nbsp;&nbsp;TMyJob=class(TJob)</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create(IOCP: TIOCP;const SrcPath, DestPath: String);</div><div class="code_line">&nbsp;&nbsp; &nbsp;destructor Destroy; override;</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure ExecProc; override;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Пользовательские данные</div><div class="code_line">&nbsp;&nbsp;PMyData=^TMyData;</div><div class="code_line">&nbsp;&nbsp;TMyData=record</div><div class="code_line">&nbsp;&nbsp; &nbsp;HSrc: THandle; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Дескрипторы входного</div><div class="code_line">&nbsp;&nbsp; &nbsp;HDest: THandle; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //и выходного файлов</div><div class="code_line">&nbsp;&nbsp; &nbsp;FileSize: LARGE_INTEGER; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Размер исходного файла</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopiedSize: LARGE_INTEGER; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Текщий размер скопированных данных</div><div class="code_line">&nbsp;&nbsp; &nbsp;Buffer: PByte; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Буфер для копирования</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;Form1: TForm1;</div><div class="code_line">&nbsp;&nbsp;IOCP: TIOCP=nil; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Экземпляр класса IOCP</div><div class="code_line">&nbsp;&nbsp;Job: TMyJob=nil; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Задание для копирования</div><div class="code_line">&nbsp;</div><div class="code_line">//Функция получения размера файла</div><div class="code_line">function GetFileSizeEx(hFile: THandle; out lpFileSize: LARGE_INTEGER): BOOL; stdcall; external &#39;kernel32.dll&#39;;</div><div class="code_line">&nbsp;</div><div class="code_line">implementation</div><div class="code_line">&nbsp;</div><div class="code_line">{$R *.dfm}</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TForm1.Button1Click(Sender: TObject);</div><div class="code_line">begin</div><div class="code_line">//Создаём экземпляр класса IOCP вместе с пулом потоков</div><div class="code_line">&nbsp;&nbsp;IOCP := TIOCP.Create;</div><div class="code_line">&nbsp;</div><div class="code_line">//В констркторе открываем входной и выходной файлы, инициализируем структуры</div><div class="code_line">&nbsp;&nbsp;Job:= TMyJob.Create(IOCP,&#39;d:\temp\temp.iso&#39;, &#39;d:\temp\temp_.iso&#39;);</div><div class="code_line">&nbsp;</div><div class="code_line">//Связываем файлы в IOCP</div><div class="code_line">&nbsp;&nbsp;Job.Associate(PMyData(JOb.UserData)^.HSrc);</div><div class="code_line">&nbsp;&nbsp;Job.Associate(PMyData(JOb.UserData)^.HDest);</div><div class="code_line">//Фиктивный вызов IOCP для запуска проыесса копирования</div><div class="code_line">&nbsp;&nbsp;Job.Complete(coWrite);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TForm1.Button2Click(Sender: TObject);</div><div class="code_line">begin</div><div class="code_line">//Освобождение всех потоков и IOCP</div><div class="code_line">&nbsp;&nbsp;FreeAndNil(IOCP);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TForm1.Timer1Timer(Sender: TObject);</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;PD: PMyData;</div><div class="code_line">&nbsp;&nbsp;CopiedSize: Int64;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;(Sender as TTimer).Enabled := False;</div><div class="code_line">&nbsp;&nbsp;if Assigned(Job) then</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">//Пользовательские данные заполняются в TMyJob.ExecProc</div><div class="code_line">&nbsp;&nbsp; &nbsp;PD := Job.UserData;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Job.CS.Enter; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Синхронизация доступа из разных потоков</div><div class="code_line">&nbsp;&nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;CopiedSize := PD^.CopiedSize.QuadPart;</div><div class="code_line">&nbsp;&nbsp; &nbsp;finally</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Job.CS.Leave;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Label1.Caption := &#39;Скопировано &#39;+FormatFloat(&#39;#,##&#39;,CopiedSize);</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Job.State = jsCompleted then</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Label1.Caption := &#39;Копирование закончено, скопировано &#39;+FormatFloat(&#39;#,##&#39;,CopiedSize);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;FreeAndNil(Job);</div><div class="code_line">&nbsp;&nbsp; &nbsp;end</div><div class="code_line">&nbsp;&nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">//Жив ли порт завершения в/в?</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;if not Job.CheckIOCP then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Label1.Caption := &#39;Копирование закончено (ошибка IOCP), скопировано &#39;+FormatFloat(&#39;#,##&#39;,CopiedSize);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;FreeAndNil(Job);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;(Sender as TTimer).Enabled := True;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;</div><div class="code_line">{ TMyJob }</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TMyJob.Create(IOCP: TIOCP;const SrcPath, DestPath: String);</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;PD: PMyData;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;inherited Create(IOCP);</div><div class="code_line">&nbsp;&nbsp;New(PD);</div><div class="code_line">&nbsp;&nbsp;UserData :=PD;</div><div class="code_line">&nbsp;&nbsp;PD^.Buffer := nil;</div><div class="code_line">&nbsp;</div><div class="code_line">//VirtualAlloc используется для того, чтобы страницы памяти были выровнены по границе 64К</div><div class="code_line">&nbsp;&nbsp;PD^.Buffer := VirtualAlloc(nil,BufSize,MEM_COMMIT,PAGE_READWRITE);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;PD^.HSrc :=</div><div class="code_line">&nbsp;&nbsp; &nbsp;CreateFile(PChar(SrcPath),</div><div class="code_line">&nbsp;&nbsp; &nbsp;GENERIC_READ,</div><div class="code_line">&nbsp;&nbsp; &nbsp;FILE_SHARE_READ,</div><div class="code_line">&nbsp;&nbsp; &nbsp;nil,</div><div class="code_line">&nbsp;&nbsp; &nbsp;OPEN_EXISTING,</div><div class="code_line">&nbsp;&nbsp; &nbsp;FILE_FLAG_OVERLAPPED,</div><div class="code_line">&nbsp;&nbsp; &nbsp;0);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;if not GetFileSizeEx(PD^.HSrc, PD^.FileSize) then raise Exception.Create(SysErrorMessage(GetLastError));</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;PD^.HDest :=</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;CreateFile(PChar(DestPath),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;GENERIC_WRITE,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;0,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;nil,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;CREATE_ALWAYS,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;FILE_FLAG_OVERLAPPED,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;0);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;if PD^.HDest=INVALID_HANDLE_VALUE then</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;raise Exception.Create(SysErrorMessage(GetLastError));</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;PD^.CopiedSize.QuadPart := 0;</div><div class="code_line">&nbsp;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">destructor TMyJob.Destroy;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;if PMyData(UserData)^.Buffer&#60;&#62;nil</div><div class="code_line">&nbsp;&nbsp; &nbsp;then VirtualFree(PMyData(UserData)^.Buffer,0,MEM_RELEASE);</div><div class="code_line">&nbsp;&nbsp;if PMyData(UserData)^.HSrc&#60;&#62;0 then CloseHandle(PMyData(UserData)^.HSrc);</div><div class="code_line">&nbsp;&nbsp;if PMyData(UserData)^.HDest&#60;&#62;0 then CloseHandle(PMyData(UserData)^.HDest);</div><div class="code_line">&nbsp;&nbsp; Dispose(PMyData(UserData));</div><div class="code_line">&nbsp;&nbsp;inherited;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">//Эта процедура вызывается при обработке завершения операции ввода/вывода в пуле потоков</div><div class="code_line">procedure TMyJob.ExecProc;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;PD: PMyData;</div><div class="code_line">&nbsp;&nbsp;dwNumBytes: Cardinal;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;PD := UserData;</div><div class="code_line">&nbsp;</div><div class="code_line">// &nbsp;if (State=jsError) or (State=jsCompleted) then Exit;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;case CodeOp of</div><div class="code_line">&nbsp;&nbsp; &nbsp;coRead: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Закончена операция чтения</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CodeOp := coWrite; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Следующая операия - запись</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if not WriteFile(PD^.HDest,PD^.Buffer^,NumBytes,dwNumBytes,OV) then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ErrorCode := GetLastError;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ErrorCode&#60;&#62;ERROR_IO_PENDING then &nbsp; &nbsp; &nbsp; //Операция жолжна быть поставлена в очередь</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;State := jsError;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else ErrorCode := 0;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;coWrite: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Закончена операция записи</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CodeOp := coRead; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Следующая операия - чтение</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CS.Enter;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;try</div><div class="code_line">//В пользовательских данных ведём подсчёт уже записанного объёма</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PD^.CopiedSize.QuadPart := PD^.CopiedSize.QuadPart + NumBytes;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;finally</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CS.Leave;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;OV^.Offset := PD^.CopiedSize.LowPart;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;OV^.OffsetHigh := PD^.CopiedSize.HighPart;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if PD^.CopiedSize.QuadPart&#60;PD^.FileSize.QuadPart then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if not ReadFile(PD^.HSrc,PD^.Buffer^,BufSize,dwNumBytes,OV) then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ErrorCode := GetLastError;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ErrorCode&#60;&#62;ERROR_IO_PENDING then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;State := jsError;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else ErrorCode := 0;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;end</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;State := jsCompleted;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">end.</div></ol></div></div></div></div><br>
</div></div>]]></description>
        <author>Демо</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      </channel>
      </rss>
	