СПЗ — Лабораторная работа №2 Процессы

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

Тема: «Процессы и их создание в Win32 API для ОС MS Windows».
Цель: Изучение процессов и потоков в операционной системе Windows.

Теоретическая часть

В Windows под процессом понимается объект ядра, которому принадлежат системные ресурсы, используемые приложением. Поэтому можно сказать, что в Windows процессом является приложение. Выполнение каждого процесса начинается с первичного потока. В процессе своего исполнения процесс может создавать другие потоки. Исполнение процесса заканчивается при завершении работы всех его потоков. Процесс может быть также завершен вызовом функций ExitProcess и TerminateProcess.
Новый процесс в Windows создается вызовом функции CreateProcess, которая имеет следующий прототип:

BOOLCreateProcess(
LPCTSTR lpApplicationName, //имя исполняемого модуля
LPTSTR lpCommandLine, //командная строка
LPSECURITY_ATTRIBUTES lpProcessAttributes, // атрибуты защиты процесса
LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибуты защиты потока
BOOL bInheritHandle, наследуемый ли дескриптор
DWORD dwCreationFlags, //флаги создания процесса
LPVOID lpEnvironment, //блок новой среды окружения
LPCTSTR lpCurrentDirectory, //текущий каталог
LPSTARTUPINFO lpStartUpInfo, //вид главного окна
LPPROCESS_INFORMATION lpProcessInformation // информация о процессе
);

Функция CreateProcess возвращает значение TRUE, если процесс был создан успешно. В противном случае эта функция возвращает значение FALSE.
Процесс, который создает новый процесс, называется родительским процессом (parent process) по отношению к создаваемому процессу. Новый же процесс, который создается другим процессом, называется дочерним процессом (child process) по отношению к процессу родителю.
Сейчас мы опишем только назначение некоторых параметров функции CreateProcess. Остальные параметры этой функции будут описываться по мере их использования. Первый параметр lpApplicationName определяет строку с именем exe-файла, который будет запускаться при создании нового процесса. Эта строка должна заканчиваться нулем и содержать полный путь к запускаемому файлу. Для примера рассмотрим следующую программу, которая выводит на консоль свое имя и параметры.

Программа 1.

// Консольный процесс, который выводит на консоль свое имя и параметры
#include
#include
int main(int argc, char *argv[])
{
int i;
puts("I am created.");
puts("\nMy name is: ");
puts(argv[0]);
for (i = 1; i < argc; i++)
printf ("\n My %d parameter = %s", i, argv[i]);
puts("\nPress any key to finish.\n");
getch();
return 0;
}
Создадим из этой программы exe-файл, который расположим на диске C и назовем ConsoleProcess.exe. Тогда этот exe-файл может быть запущен из другого приложения следующим образом.

Программа 2.

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

#include
#include
#include
int main()
{
char lpszAppName[] = "C:\\ConsoleProcess.exe";

STARTUPINFO si;
PROCESS_INFORMATION piApp;

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);

// соз даем новый консольный процесс
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE,NULL,NULL,&si ,&piApp))
{
puts("The new process is not created.\n");
puts("Check a name of the process.\n");
puts("Pressany key tofi ni sh.\n");
getch();
return 0;
}

puts("The new process is created.\n");
// жде м завершения созданного прцесса
WaitForSingleObject(piApp.hProcess, INFINITE);
// зак рываем дескрипторы этого процесса в текущем процессе
CloseHandle(piApp.hThread);
CloseHandle(piApp.hProcess);

return 0;
}

Отметим в последней программе два момента. Во-первых, перед запуском
консольного процесса ConsoleProcess.exe все поля структуры si типа
STARTUPINFO должны заполняться нулями. Это делается при помощи вызова
функции ZeroMemory, которая предназначена для этой цели и имеет
следующий прототип:

VOIDZeroMemory(
PVOID Destination, //адр ес блока памяти
SIZE_T Length дл/и/ на блока памяти
);

В этом случае вид главного окна запускаемого приложения определяется по
умолчанию самой операционной системой Windows. Во-вторых, в параметре
dwCreationFlags устанавливается флаг CREATE_NEW_CONSOLE. Это говорит
системе о том, что для нового создаваемого процесса должна быть создана
новая консоль. Если этот параметр будет равен NULL, то новая консоль для
запускаемого процесса не создается и весь консольный вывод нового процесса
будет направляться в консоль родительского процесса.
Структура piApp типа PROCESS_INFORMATION содержит
идентификаторы и дескрипторы нового создаваемого процесса и его главного
потока. Мы не используем эти дескрипторы в нашей программе и поэтому
закрываем их. Значение FALSE параметра bInheritHandle говорит о том, что эти
дескрипторы не являются наследуемыми. О наследовании дескрипторов мы
поговорим подробнее в одном из следующих параграфов этой главы.
Теперь запустим наш новый консольный процесс другим способом,
используя второй параметр функции CreateProcess. Это можно сделать при
помощи следующей программы.

Программа 3.

// Пример процесса, который создает новое консольное приложение с новой консолью

#include
#include

int main()
{
char lpszCommandLine[] = "C:\\01-1-ConsoleProcess.exe p1 p2 p3";

STARTUPINFO si;
PROCESS_INFORMATION piCom;

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);

// создаем новый консольный процесс
CreateProcess(NULL, lpszCommandLine, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE,NULL,NULL,&si ,&piCom);
// зак рываем дескрипторы этого процесса
CloseHandle(piCom.hThread);
CloseHandle(piCom.hProcess);

cputs("The new process is created.\n");
cputs("Press any key to finish.\n"); getch();
return 0;
}

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

· каталог из которого запущено приложение;
текущий каталог родительского процесса;

· системный каталог Windows;

· каталог Windows;

· каталоги, которые перечислены в переменной PATH среды окружения.
Для иллюстрации сказанного запустим приложение Notepad.exe, используя
командную строку. Программа, запускающая блокнот из командной строки,
выглядит следующим образом.

Программа 4.

// Пример запуска процесса Notepad

#include
#include

int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;

// зап олняем значения структуры STARTUPINFO по умолчанию
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);

// зап ускаем процесс Notepad
if(!CreateProcess(
NULL, //имя не задаем
"Notepad.exe", // командная строка, первая лексема указывает имя программы
NULL, //атрибуты защиты процесса устанавливаем по умолчанию
NULL, //атрибуты защиты первичного потока по умолчанию
FALSE, // дескрипторы текущего процесса не наследуются новым процессом
0, //поумолчанию NORMAL_PRIORITY_CLASS
NULL, //используем среду окружения вызывающего процесса
NULL, //текущий диск и каталог, как и в вызывающем процессе
&si, //вид главного окна - по умолчанию
&pi //здесь будут дескрипторы и идентификаторы
//нового процесса и его первичного потока
)
)
{
cout << "The mew process is not created." << endl
<< "Check a name of the process." << endl;
return 0;
} Sleep(1000); // нем ного подождем и закончим свою работу

// зак роем дескрипторы запущенного процесса в текущем процессе
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);

return 0;
}

Завершение процессов.

Процесс может завершить свою работу вызовом функции ExitProcess,
которая имеет следующий прототип:

VOIDExit Process(
UINT uExitCode //код возврата для всех потоков
);

При вызове функции ExitProcess завершаются все потоки процесса с кодом
возврата, который является параметром этой функции. Приведем пример
программы, которая завершает свою работу вызовом функции ExitProcess.


Программа 5.

// Пример завершения процесса функцией ExitProcess

#include
#include

volatile UINT count;
volatile char c;

void thread()
{
for ( ; ; )
{
count++;
Sleep(100);
}
}

int main()
{
HANDLE hThread;
DWORD IDThread;

hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread, NULL, 0, &IDThread);
if (hThread == NULL)
return GetLastError();

for ( ; ; )
{
cout << "Input 'y' to display the count or 'e' to exit: ";
cin>>( char)c;
if (c == 'y') cout << "count = " << count << endl;
if (c == 'e')
ExitProcess(1);
}
}

Один процесс может завершить другой процесс при помощи вызова
функции TerminateProcess, которая имеет следующий прототитп:

BOOLTer minateProcess(
HANDLE hProcess,
UINT uExitCode
);

Если функция TerminateProcess выполнилась успешно, то она возвращает
значение равно TRUE. В противном случае возвращаемое значение равно
FALSE. Функция TerminateProcess завершает работу процесса, но не
освобождает все ресурсы, принадлежащие этому процессу. Поэтому эта
функция должна вызываться только в аварийных ситуациях при зависании
процесса.
Приведем программу, которая демонстрируют работу функции
TerminateProcess. Для этого сначала создадим бесконечный процесс-счетчик,
который назовем ConsoleProcess.exe и расположим на диске C.

Программа 6.

// Пример бесконечного процесса

#include
#include

int count;

void main()
{
for ( ; ; )
{
count++;
Sleep(1000);
cout << "count = " << count << endl;
}
}

Ниже приведена программа, которая создает этот процесс, а потом
завершает его по требованию пользователя.

Программа 7.

// Пример процесса, который создает другое консольное приложение с новой консолью,
// а потом завершает его при помощи функции TerminateProcess

#include
#include
#include

int main()
{ char lpszAppName[] = "C:\\ConsoleProcess.exe";

STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);

// создаем новый консольный процесс
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE,NULL,NULL,&si ,&pi ))
{
puts("The new process is not created.\n");
puts("Check a name of the process.\n");
puts("Pressany key tofi ni sh.\n");
getch();
return 0;
}

puts("The new process is created.\n");

while(true)
{
char c;

puts("Input 't' to terminate the new console process: ");
c=getch();
if (c == 't')
{
puts("t\n");
//завершаем новый процесс
TerminateProcess(pi.hProcess,1);
break;
}
}


// закрываем дескрипторы нового процесса в текущем процессе
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);

return 0;
}

Задача.

Написать программы двух консольных процессов Parent и Child, которые
выполняют следующие действия.
Процесс Parent:
1. Создает бинарный файл, записи которого имеют следующую
структуру:
struct emp
{
int n um; // номер зачетки
charna me[10]; // имя студента
double grade; // средний бал
};
Имя файла и данные о студентах вводятся с консоли.
2. Выводит созданный файл на консоль.
3. Запрашивает с консоли номер зачетки, имя студента и новый средний
бал этого студента.
4. Формирует командную строку, которая содержит имя созданного
файла и информацию, полученную в пункте 3.
5. Запускает дочерний процесс Child, которому как параметр
передается командная строка, сформированная в пункте 4.
6. Ждет завершения работы процесса Child.
7. Выводит откорректированный файл на консоль.
8. Завершает свою работу.
Процесс Child:
1. Выводит на консоль информацию, полученную через командную
строку.
2. Корректирует в файле, созданном процессом Parent, нужную запись,
т.е. устанавливает новый средний бал студента.
3. Завершает свою работу.
Примечание.
Для ожидания завершения работы процесса Child использовать
функцию:
DWORD WaitForSingleObject(
HANDLE hHandle, // д ескриптор объекта
DWORD dwMilliseconds
// и нтервал ожидания в миллисекундах
);
где второй параметр установить равным INFINITE, например

WaitForSingleObject(hProcess, INFINITE);
// ждать завершения процесса
Здесь hProcess – дескриптор процесса Child.

Заголовок 115

Приложенные файлы

  • doc 22445920
    Размер файла: 75 kB Загрузок: 0

Добавить комментарий