/* Глава 6. timep. */
#include "EvryThng.h"
int _tmain(int argc, LPTSTR argv[]) {
STARTUPINFO Startup;
PROCESS_INFORMATION ProcInfo;
union { /* Эта структура используется для выполнения арифметических операций с участием временных параметров. */
LONGLONG li;
FILETIME ft;
} CreateTime, ExitTime, ElapsedTime;
FILETIME KernelTime, UserTime;
SYSTEMTIME ElTiSys, KeTiSys, UsTiSys, StartTimeSys, ExitTimeSys;
LPTSTR targv = SkipArg(GetCommandLine());
OSVERSIONINFO OSVer;
BOOL IsNT;
HANDLE hProc;
OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&OSVer);
IsNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
/* NT (все версии) возвращает VER_PLATFORM_WIN32_NT. */
GetStartupInfo(&StartUp);
GetSystemTime(&StartTimeSys);
/* Выполнить командную строку; дождаться завершения процесса. */
CreateProcess (NULL, targv, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartUp, &ProcInfo);
/* Убедиться в наличии ВСЕХ НЕОБХОДИМЫХ прав доступа к процессу. */
DuplicateHandle(GetCurrentProcess(), ProcInfo.hProcess, GetCurrentProcess(), &hProc, PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, 0);
WaitForSingleObject(hProc, INFINITE);
GetSystemTime (&ExitTimeSys);
if (IsNT) { /* Windows NT. Для процесса вычисляется истекшее время, время выполнения в режиме ядра и время выполнения в пользовательском режиме. */
GetProcessTimes(hProc, &CreateTime.ft, &ExitTime.ft, &KernelTime, &UserTime);
ElapsedTime.li = ExitTime.li – CreateTime.li;
FileTimeToSystemTime(&ElapsedTime.ft, &ElTiSys);
FileTimeToSystemTime(&KernelTime, &KeTiSys);
FileTimeToSystemTime(&UserTime, &UsTiSys);
_tprintf(_T("Истекшее время: %02d:%02d:%02d:%03d\n"), ElTiSys.wHour, ElTiSys.wMinute, ElTiSys.wSecond, ElTiSys.wMilliseconds);
_tprintf(_T("Пользовательское время: %02d:%02d:%02d:%03d\n"), UsTiSys.wHour, UsTiSys.wMinute, UsTiSys.wSecond, UsTiSys.wMilliseconds);
_tprintf(_T("Системное время: %02d:%02d:%02d:%03d\n"), KeTiSys.wHour, KeTiSys.wMinute, KeTiSys.wSecond, KeTiSys.wMilliseconds);
} else {
/* Windows 9x и СЕ. Вычисляется лишь истекшее время. */
…
}
CloseHandle(ProcInfo.hThread);
CloseHandle(ProcInfo.hProcess);
CloseHandle(hProc);
return 0;
}
Использование команды timep
Теперь мы можем воспользоваться командой timep для анализа производительности различных вариантов программ копирования файлов и их преобразования из ASCII в Unicode, таких, например, как утилиты atou (программа 2.4) и sortMP (программа 5.5). Некоторые из полученных результатов и краткий их анализ представлены в приложении В.
Обратите внимание, что для таких программ, как grepMP, тестирование предоставляет системное и пользовательское время только для родительских процессов. Объекты задач, описанные в конце настоящей главы, позволяют собрать информацию, касающуюся группы процессов. Как показано в приложении В, в случае SMP-систем производительность может повышаться за счет того, что отдельные процессы, вернее, потоки, выполняются на различных процессорах. Выигрыш в производительности возможен и в тех случаях, когда файлы располагаются на различных физических дисках.
Генерация управляющих событий консоли
Прерывание выполнения процесса извне может порождать проблемы, поскольку это лишает процесс возможности произвести необходимую завершающую обработку данных и очистку ресурсов. Воспользоваться SEH в данном случае нельзя ввиду того, что не существует общего метода, который позволял бы одному процессу возбуждать исключения в другом[25]. В то же время, с учетом некоторых ограничений, механизм управляющих событий консоли делает возможной передачу одним процессом другому управляющих сигналов, или событий, консоли. В программе 4.5 было продемонстрировано, как установить обработчик для перехвата сигналов и организовать генерацию исключений этим обработчиком. В указанном примере сигнал генерировался по приказу пользователя средствами пользовательского интерфейса.
Таким образом, вполне можно добиться того, чтобы один процесс генерировал сигнал, соответствующий определенному событию, в другом указанном процессе или группе процессов. Вспомните флаг CREATE_NEW_PROCESS_GROUP функции CreateProcess. Если этот флаг установлен, то идентификатор нового процесса идентифицирует группу процессов и является корневым (root) процессом данной группы. Все новые процессы, создаваемые данным родительским процессом, будут автоматически попадать в эту группу до тех пор, пока при вызове функции CreateProcess не будет использован флаг CREATE_NEW_PROCESS_GROUP. Сгруппированные процессы аналогичны группам процессов в UNIX.
Процесс может генерировать события CTRL_C_EVENT или CTRL_BREAK_EVENT в указанной группе процессов, идентифицируя ее с помощью идентификатора корневого процесса. Консоль целевых процессов должна совпадать с консолью процесса, генерирующего событие. В частности, вызывающий процесс не может быть создан с использованием собственной консоли (посредством флагов CREATE_NEW_CONSOLE или DETACHED_PROCESS).