`
Читать книги » Книги » Компьютеры и Интернет » Программирование » Джонсон Харт - Системное программирование в среде Windows

Джонсон Харт - Системное программирование в среде Windows

1 ... 56 57 58 59 60 ... 142 ВПЕРЕД
Перейти на страницу:

• Включите директиву #define _MT во все исходные файлы, в которых используется библиотека С.

• Добавьте включаемый файл <process.h>, содержащий определения функций _beginthreadex и _endthreadex.

• Создайте потоки с помощью функции _beginthreadex; не применяйте для этой цели функцию CreateThread.

• Завершите потоки посредством функции _endthreadex или просто воспользуйтесь оператором return в конце функции потока.

В приложении А вы найдете указания относительно того, как создавать многопоточные приложения. В частности, можно, и даже рекомендуется, указывать библиотеку и определять константу _МТ непосредственно в среде разработки.

Именно так будут построены все наши примеры, и функция CreateThread никогда не будет непосредственно применяться в программах даже в тех случаях, когда библиотека С в функциях потоков не используется. 

Библиотеки с многопоточной поддержкой

При проектировании пользовательских библиотек следует уделять самое пристальное внимание тому, чтобы избежать возникновения проблем, связанных с параллельным выполнением нескольких потоков, особенно в тех случаях, когда речь идет о сохранении информации о состоянии процессов. Одна из возможных стратегий демонстрируется в примере в главе 12 (программа 12.4), где библиотека DLL для сохранения информации о состоянии использует отдельный параметр.

Еще один пример в главе 12 (программа 12.5) иллюстрирует альтернативный подход, в котором применяется функция DllMain и TLS, описанные далее в настоящей главе.

Пример: многопоточный поиск контекста

В программе 6.1 (grepMP) для выполнения одновременного поиска текстового шаблона в нескольких файлах использовались процессы. Программа 7.1 (grepMT), которая включает исходный код функции поиска текстового шаблона grep, обеспечивает выполнение поиска несколькими потоками в рамках одного процесса. Код функции поиска основан на вызовах функций файлового ввода/вывода библиотеки С. Основная программа аналогична той, которая предлагалась в варианте реализации, основанном на использовании процессов.

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

Мы увидим, однако, что в сочетании с портами завершения ввода/вывода операции асинхронного ввода/вывода становятся очень полезным, а часто и необходимым средством в тех случаях, когда количество потоков очень велико.

В иллюстративных целях в программу grepMT введено дополнительное отличие по сравнению с программой grepMP. В данном случае функция WaiForMultipleObjects ожидает завершения не всех потоков, а только одного. Соответствующая информация выводится без ожидания завершения других потоков. В большинстве случае порядок завершения потоков будет меняться от одного запуска программы к другому. Программу легко видоизменить таким образом, чтобы результаты отображались в порядке указания аргументов в командной строке; для этого будет достаточно сымитировать программу grepMP. 

Наконец, обратите внимание на ограничение в 64 потока, обусловленное значением константы MAXIMUM_WAIT_OBJECTS, которая ограничивает количество дескрипторов при вызове функции WaitForMultipleObjects. Если у вас возникнет необходимость в большем количестве потоков, организуйте для функций WaitForSingleObjects или WaitForMultipleObjects соответствующий цикл.

Предостережение

Программа grepMP осуществляет асинхронный ввод/вывод в том смысле, что отдельные потоки выполняют параллельное синхронное чтение различных файлов, которые блокируются до момента завершения операции чтения. Можно также организовать параллельное чтение одного и того же файла, если у него имеются различные дескрипторы (обычно, по одному дескриптору для каждого потока). Эти дескрипторы должны быть сгенерированы функцией CreateFile, а не функцией DuplicateHandle. В главе 14 описывается асинхронный ввод/вывод, осуществляемый как с использованием, так и без использования пользовательских потоков, а в примере, доступном на Web-сайте (программа atouMT, описанная в главе 14), операции ввода/вывода выполняются с использованием нескольких потоков по отношению к одному и тому же файлу.

Программа 7.1. grepMT: многопоточный поиск текстового шаблона 

/* Глава 7. grepMT. */

/* Параллельный поиск текстового шаблона — версия, использующая несколько потоков. */

#include "EvryThng.h"

typedef struct { /* Структура данных потока поиска. */

 int argc;

 TCHAR targv[4][МАХ_РАТН];

} GREP_THREAD_ARG;

typedef GREP_THREAD_ARG *PGR_ARGS;

static DWORD WINAPI ThGrep(PGR_ARGS pArgs);

int _tmain(int argc, LPTSTR argv[]) {

 GREP_THREAD_ARG * gArg;

 HANDLE * tHandle;

 DWORD ThdIdxP, ThId, ExitCode;

 TCHAR CmdLine[MAX_COMMAND_LINE];

 int iThrd, ThdCnt;

 STARTUPINFO Startup;

 PROCESS_INFORMATION ProcessInfo;

 GetStartupInfo(&StartUp);

 /* Основной поток: создает отдельные потоки поиска на основе функции "grep" для каждого файла. */

 tHandle = malloc((argc – 2) * sizeof(HANDLE));

 gArg = malloc((argc – 2) * sizeof(GREP_THREAD_ARG));

 for (iThrd = 0; iThrd < argc – 2; iThrd++) {

  _tcscpy(gArg[iThrd].targv[1], argv[1]); /* Pattern. */

  _tcscpy(gArg[iThrd].targv[2], argv[iThrd + 2]);

  GetTempFileName /* Имя временного файла. */

   (".", "Gre", 0, gArg[iThrd].targv[3]); 

  gArg[iThrd].argc = 4;

  /* Создать рабочий поток для выполнения командной строки. */

  tHandle[iThrd] = (HANDLE)_beginthreadex(NULL, 0, ThGrep, &gArg[iThrd], 0, &ThId);

 }

 /* Перенаправить стандартный вывод для вывода списка файлов. */

 Startup.dwFlags = STARTF_USESTDHANDLES;

 Startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);

 /* Выполняются все рабочие потоки. Ожидать их завершения. */

 ThdCnt = argc – 2;

 while (ThdCnt > 0) {

  ThdIdxP = WaitForMultipleObjects(ThdCnt, tHandle, FALSE, INFINITE);

  iThrd = (int)ThdIdxP – (int)WAIT_OBJECT_0;

  GetExitCodeThread(tHandle [iThrd], &ExitCode);

  CloseHandle(tHandle [iThrd]);

  if (ExitCode ==0) { /* Шаблон найден. */

   if (argc > 3) {

    /* Вывести имя файла, если имеется несколько файлов. */

    _tprintf(_T("n**Результаты поиска – файл: %sn"), gArg[iThrd].targv [2]);

    fflush(stdout);

   }

   /* Использовать программу "cat" для перечисления результирующих файлов. */

   _stprintf(CmdLine, _T("%s%s"), _Т("cat "), gArg [iThrd].targv[3]);

   CreateProcess(NULL, CmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartUp, &ProcessInfo);

   WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

   CloseHandle(ProcessInfo.hProcess);

   CloseHandle(ProcessInfo.hThread);

  }

  DeleteFile(gArg[iThrd].targv[3]);

  /* Скорректировать массивы потоков и имен файлов. */

  tHandle[iThrd] = tHandle[ThdCnt – 1];

  _tcscpy(gArg[iThrd].targv[3], gArg[ThdCnt – 1].targv[3]);

  _tcscpy(gArg[iThrd].targv[2], gArg[ThdCnt – 1].targv[2]);

  ThdCnt--;

 }

}

/* Прототип функции контекстного поиска:

static DWORD WINAPI ThGrep(PGR_ARGS pArgs){ } */

Потоки и производительность

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

В то же время, существует весьма распространенное заблуждение, суть которого состоит в том, что отмеченный параллелизм, независимо от того, касается ли он использования нескольких процессов, как в случае grepMP, или же применения нескольких потоков, как в случае grepMT, способен приводить к повышению производительности лишь в случае SMP-систем. Выигрыш в производительности можно получить и при использовании нескольких дисков, а также при любом другом распараллеливании в системе хранения. Во всех подобных случаях операции ввода/вывода с участием нескольких файлов будут осуществляться в параллельном режиме.

1 ... 56 57 58 59 60 ... 142 ВПЕРЕД
Перейти на страницу:

Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Джонсон Харт - Системное программирование в среде Windows, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

Комментарии (0)