Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
МУ по лабораторным по ОС.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
649 Кб
Скачать

Индивидуальное задание

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

Отчет по лабораторной работе должен содержать тему, цель, содержание индивидуального задания, листинг программы, скрин-шот результатов расчета.

Лабораторная работа № 7

Асинхронный ввод-вывод в режиме пользователя

Цель: Получить навыки в следующих предметных областях:

  • работа с файлами в режиме ввода-вывода с перекрытием (input/output overlapped).

Теоретические сведения

Функция CreateFile

Функция создаёт указатель на новое устройство типа:

  • Файл

  • Канал

  • mailslot (почтовый канал)

  • коммуникационный ресурс (например COM порт)

  • дисковые устройства

  • консоли

  • директории (открывает их)

Все эти функции описаны в одном файле windows.h.

Описание:

1

2

3

4

5

6

7

8

9

HANDLE CreateFile(

   LPCTSTR lpFileName,        // Указатель на имя файла (устройства)

   DWORD dwDesiredAccess,  //Параметры доступа

   DWORD dwShareMode,        //Разделяемый доступ

   LPSECURITY_ATTRIBUTES lpSecurityAttributes,    //безопасность

   DWORD dwCreationDistribution,// Описание

   DWORD dwFlagsAndAttributes,     // Атрибуты файла

   HANDLE hTemplateFile      // Файл шаблона

);

Файл создается следующим образом:

1

2

3

4

5

6

7

{

   Handle FileHandle;

   FileHandle=CreateFile("file1.txt",GENERIC_READ |

      GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_NEW,

      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);

   CloseHandle(FileHandle);

}

Теперь рассмотрим используемые параметры:

  • параметры GENERIC_READ и GENERIC_WRITE определяют доступ на чтение и запись. Однако можно указать что-то одно в зависимости от ваших потребностей. Если в качестве этого параметра указать 0, то в этом случае функция отработает успешно, однако никакого доступа к файлу не получит. Этот вариант удобно использовать для теста существования файла.

  • параметры FILE_SHARE_WRITE or FILE_SHARE_READ — общий доступ на чтение и запись к данному файлу. То есть файл будет доступен при одновременном использовании несколькими процессами.

  • следующий параметр — атрибут безопасности неопределен. То есть все дескрипторы будут доступны дочерним процессам вашего приложения.

  • параметр CREATE_NEW указывает на создание нового файла. Если файл с заданным именем существует, то будет возвращен код ошибки. Если использовать параметр CREATE_ALWAYS, то в этом случае, если файл существует, то он будет перезаписан.

  • параметр FILE_ATTRIBUTE_NORMAL определяет файлу стандартные атрибуты. А если указывать флаг FILE_FLAG_OVERLAPPED, то файл будет доступен в асинхронном режиме.

  • так как мы не используем шаблоны, то в качестве этого параметра указываем ноль.

Функция OpenFile

Данная функция, по сути своей, предназначена для открытия файлов или устройств. Функция OpenFile в случае успеха возвращает дескриптор (указатель) открываемого файла. В случае неудачи мы получим в качестве дескриптора значение INVALID_HANDLE_VALUE.

1

2

3

4

5

HFILE WINAPI OpenFile(

  LPCSTR lpFileName,

  LPOFSTRUCT lpReOpenBuff,

  UINT uStyle

);

Теперь рассмотрим используемые параметры:

  • в качестве первого параметра указывается имя открываемого файла.

  • вторым параметром является специальная структура открываемого файла, в которую заносятся сведения о файле.

  • 3-й параметр представляет собой совокупность флагов для работы с файлом.

Собственно, как открыть файл:

1

2

3

4

5

6

{

   Handle FileHandle;

   FileHandle= OpenFile("Settings.ini", Buf, OF_Create |

                            OF_READWRITE | OF_SHARE_EXCLUSIVE);

   CloseHandle(FileHandle);

}

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

Функция ReadFile

Данная функция предназначена для чтения файлов или с устройств ввода/вывода. В случае успешного выполнения операции  чтения, возвращается логическое значение true, иначе false. А функция GetLastError вернет ERROR_HANDLE_EOF.

1

2

3

4

5

6

7

BOOL ReadFile(HANDLE hFile, //собственно указатель на файл

         LPVOID lpBuffer,  // указатель на буфер - куда записываем считанные данные

         DWORD nNumberOfBytesToRead, //объем считываемых данных, не может превышать размер буфера

         LPDWORD lpNumberOfBytesRead, //фактический размер считанных данных

         LPOVERLAPPED lpOverlapped   // флаг режима доступа к файлу:

                                    // асинхронный (FILE_FLAG_OVERLAPPED) или синхронный

// (NULL)

);

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

{

Handle FileHandle;

char Buf[1000];

...

     ReadFile(FileHandle, Buf, sizeof(buf),NULL);

...

}

Функция WriteFile

Данная функция предназначена для записи в файл или устройство ввода/вывода. С ней все аналогично что и с функцией ReadFile(). В случае успешного выполнения операции  чтения, возвращается логическое значение true, иначе false. А функция GetLastError вернет ERROR_HANDLE_EOF.

1

2

3

4

5

6

7

BOOL WriteFile(HANDLE hFile, //собственно указатель на файл

         LPVOID lpBuffer,  // указатель на буфер - откуда записываем данные в  файл

         DWORD nNumberOfBytesToWrite, //объем записываемых данных

         LPDWORD lpNumberOfBytesWrite, //фактический размер записанных данных

         LPOVERLAPPED lpOverlapped   // флаг режима доступа к файлу: асинхронный(FILE_FLAG_OVERLAPPED)

                                    //или синхронный(NULL)

);

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

{

Handle FileHandle;

char Buf[1000];

...

     ReadFile(FileHandle, Buf, sizeof(buf),NULL);

...

}

Функция CloseHandle

Эта функция достаточно проста. Выполняет действия по освобождению указателя на файл. Ее необходимость очевидна — чтобы не засорять память ненужными указателями и позволять работу с файлами другим процессам. В качестве ее единственного параметра передается указатель на ранее открытый файл.

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

{

   Handle FileHandle;

   FileHandle= OpenFile("Settings.ini", Buf, OF_Create |

                            OF_READWRITE | OF_SHARE_EXCLUSIVE);

...

   CloseHandle(FileHandle);

}

Функция DeleteFile

Эта функция так же не отличается особой сложностью. Данная функция удаляет файл, который указан в параметре.  Функция возвращает значение true, если выполняется успешно. Иначе возвращает false, а код ошибки можно получить с помощью GetLastError.

1

2

3

BOOL WINAPI DeleteFile(

      LPCTSTR lpFileName // имя файла, который надо удалить

);

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

{

...

     DeleteFile("C:\Temp\test.txt");// если указать только

// имя файла, то будет осуществлена попытка удалить файл из папки, откуда была запущена программа

 

...

}

Функция CopyFile

Основное назначение этой функции — копирование файла. В случае успеха возвращает true, иначе — false. Код ошибки можно получить с помощью GetLastError.

1

2

3

4

5

6

BOOL CopyFile(

     LPCTSTR lpExistingFileName,// Указатель на файл, который надо копировать

     LPCTSTR lpNewFileName, // Указатель на имя файла, куда надо копировать

     BOOL bFailIfExists //если указать true, то в случае существования такого файла,

      // произойдет ошибка, если false - то существующий файл будет перезаписан.

);

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

{

...

     CopyFile("C:\Temp\test1.txt","C:\Temp\test2.txt", true); // если указать только

// имя файла, то все действия будут выполнены в папке из которой запущена программа

...

}

Функция FindFirstFile

Данная функция запускает поиск в указанной директории. Функция возвращает указатель на найденный файл, если нет, то возврат будет типа ERROR_NO_MORE_FILES.

1

2

3

4

HANDLE FindFirstFile(

    LPCTSTR lpFileName, // Строка, содержащая путь для поиска файлов.

    LPWIN32_FIND_DATA lpFindFileData // Информация о найденном файле

);

Теперь рассмотрим параметры подробней:

  • lpFileName — строка, содержащая путь для поиска файла. Эта строка может указывать на конкретный файл типа ‘c:\filename.txt’ или может хранить шаблон ‘c:\*.*’. Если указывать шаблон, то это даёт возможность перечислить все файлы удовлетворяющие шаблону.

  • lpFindFileData — структура WIN32_FIND_DATA, в которую будут записаны сведения о найденном файле.

Рассмотрим структуру WIN32_FIND_DATA немного подробнее:

1

2

3

4

5

6

7

8

9

10

11

12

typedef struct _WIN32_FIND_DATA {

          DWORD dwFileAttributes;  // Атрибуты файла

          FILETIME ftCreationTime; // Время создания

          FILETIME ftLastAccessTime;  //Время последнего доступа

          FILETIME ftLastWriteTime;   //Время последней записи в файл

          DWORD    nFileSizeHigh;     //Верхний байт размера файла

          DWORD    nFileSizeLow;      //Нижний байт размера файла

          DWORD    dwReserved0;       //Зарезервировано

          DWORD    dwReserved1;       //Зарезервировано

          TCHAR    cFileName[ MAX_PATH ];    //Имя файла

          TCHAR    cAlternateFileName[ 14 ]; //Имя файла для отображения в DOS (8:3)

} WIN32_FIND_DATA;

Атрибутами файла может быть комбинация из флагов:

  • FILE_ATTRIBUTE_ARCHIVE — архивный

  • FILE_ATTRIBUTE_COMPRESSED — сжатый

  • FILE_ATTRIBUTE_HIDDEN — скрытый

  • FILE_ATTRIBUTE_NORMAL — нормальный

  • FILE_ATTRIBUTE_OFFLINE — данные файла недоступны

  • FILE_ATTRIBUTE_READONLY — только для чтения

  • FILE_ATTRIBUTE_SYSTEM — системный

  • FILE_ATTRIBUTE_TEMPORARY — временный

Размер файла разложен на два байта. Чтоб получить полный размер файла нужно выполнить действие (FInfo.nFileSizeHigh * MAXDWORD) + FInfo.nFileSizeLow. Это не самый эффективный (эффективнее сдвигать), но самый понятный способ.

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

{

   WIN32_FIND_DATA sss;

   HANDLE f;

   f = FindFirstFile("C:\*.*", &sss);

...

   FindClose(f);

}

Функция FindNextFile

Данная функция продолжает поиск начатый функцией FindFirstFile(). Если очередной файл найден, то функция возвращает значение true, иначе  возврат будет типа ERROR_NO_MORE_FILES.

1

2

3

4

BOOL FindNextFile(

    HANDLE hFindFile,   // Указатель на файл из предыдущего поиска

    LPWIN32_FIND_DATA lpFindFileData // Информация об очередном найденном файле

);

Со вторым параметром всё ясно, из описания функции FindFirstFile. А вот первый — это указатель на файл из предыдущего поиска. Он нужен, чтобы функция FindNextFile знала, на каком файле был остановлен поиск и какой надо найти следующим.

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

8

9

10

{

   WIN32_FIND_DATA sss;

   HANDLE f;

   f = FindFirstFile("C:\*.*", &sss);

   if(f != INVALID_HANDLE_VALUE)

      do{

         ...

      }while(FindNextFile(f,&sss));

   FindClose(f);

}

Функция GetFileSize

Данная функция определяет размер файла, на который ссылается переданный указатель. Если размер файла меньше 4 Гб, то функция возвращает размер файла. Если размер файла больше 4Гб, то размер файла записан во втором параметре. В случае возникновения исключения будет возвращено значение типа INVALID_FILE_SIZE.

1

2

3

4

5

DWORD GetFileSize(

   HANDLE hFile,       // Указатель на файл

   LPDWORD lpFileSizeHigh // старший байт размера файла, в качестве

            // этого параметра можно указать NULL

);

Теперь рассмотрим рабочий пример:

1

2

3

4

5

6

7

{

DWORD FileSize;

Handle f;

...

FileSize=GetFileSize(f,NULL);

...

}

Асинхронный ввод-вывод

Асинхронный ввод-вывод реализован в некоторых UNIX-системах (есть стандарт POSIX для таких операций). Одна из наиполнейших реализаций этой технологии доступная также в системах линии Wіndows ХР, где ее называют вводом-выводом с перекрытием (overlapped І/O). Основная идея здесь заключается в том, что поток, который начал выполнять ввод-вывод, не блокируют до его завершения. Асинхронный ввод-вывод сводится к выполнению таких действий.

Поток выполняет системный вызов асинхронного ввода или вывода, который ставит операцию ввода-вывода в очередь и немедленно возвращает управление.

Поток продолжает выполнение параллельно с операцией ввода-вывода.

Когда операция ввода-вывода завершается, поток получает об этом сообщение.

Операция может быть прервана до своего завершения.

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

В Wіn32 АРЕ применяется следующий подход: для асинхронного ввода-вывода можно использовать стандартные функции файлового ввода и вывода ReadFіle() и WrіteFіle(), если в них передается последним параметром указатель на специальную структуру типа OVERLAPPED. При этом файл должен быть открыт с включенным флажком, который разрешает асинхронные операции. Для ожидания завершения ввода-вывода используют универсальную функцию ожидания, например WaіtForSіngleObject(). В простейшем случае она должна ожидать на файловом дескрипторе, для которого было выполнено ввод или вывод. Для получения результата надо использовать функцию GetOverlappedResult(), для прерывания ввода-вывода – CancelIO(). Приведем схему использования асинхронного ввода-вывода в Wіn32 АРI.

// структура - индикатор асинхронной операции

OVERLAPPED ov = { 0 };

// открыть файл с флажком асинхронного ввода-вывода

HANDLE fh = CreateFіle (.... FІLE_FLAG_OVERLAPPED,...);

// асинхронную операцию чтения задают передачей указателя на структуру ov

ReadFіle (fh, buf, sіzeof(buf), &sіze, &ov);

// ... другие действия, здесь buf пока использовать нельзя

WaіtForSіngleObject (fh, ІNFІNІTE); // ожидание завершения операции

// здесь можно использовать buf

// получение результата операции

GetOverlappedResult (fh, &ov, &nread, FALSE);