Процессы Процесс – это исполняемый экземпляр программы и набор ресурсов, которые выделяются данной исполняемой программе. Ресурсы: виртуальное адресное пространство; системные ресурсы –области физической памяти, процессорное время, файлы, растровые изображения и т.д.; модули процесса, то есть исполняемые модули, загруженные (отображенные) в его адресное пространство – основной загрузочный модуль, библиотеки динамической компоновки, драйверы устройств и т.д.; уникальный идентификационный номер, называемый идентификатором процесса; потоки (по крайней мере, один поток).
Модель процесса: Квант времени Поток A Переклю чение процесс ора Квант времени Поток B Переклю чение процесс ора Квант времени ………… Сохранение контекста текущего потока, регистров, стека и областей памяти. Определение очередного потока. Восстановление контекста очередного потока. t Планировщик процессов. Диспетчер процессов
Последовательность исполнения потоков в среде с вытесняющей многозадачностью: В системе определен квант времени (порядка десятков миллисекунд) – процессорное время выделяемое одному потоку (каждому - своё). Длительность выполнения одного потока не может превышать одного кванта. Когда это время заканчивается, диспетчер процессов переключает процессор на выполнение другого потока. При этом состояние регистров, стека и областей памяти – контекст потока, сохраняется в стеке потока. Очередность потоков определяется их состоянием и приоритетом.
Состояние процессов: Действие БлокировкаГотовность Процесс заблокирован в ожидании ввода. 2. Диспетчер выбирает другой процесс. 3. Диспетчер выбирает данный процесс. 4. Входные данные стали доступны.
Информация о процессах хранится в таблице процессов и обновляется планировщиком процессов. Реализацией процессов является таблица процессов, - линейный список (программно реализованный, как массив структур).
Регистры Счетчик команд Указатель стека Состояние процесса Приоритет Идентификатор процесса Родительский процесс Время запуска процессора Использованное время процессора Корневой каталог Рабочий каталог Дескрипторы файлов Идентификатор пользователя Некоторые поля типичной записи таблицы процессов:
Создание процесса: #include void oldman(); void recreation(); int main(){ pid_t child_pid, parent_pid; int i=0; fprintf(stdout, "Before RECREATION %i\n", parent_pid=(int) getpid()); child_pid=fork(); while(i++
#include void oldman(){ fprintf(stdout, "I'm not yet dead! My ID is %i\n", (int) getpid()); } void recreation(){ fprintf(stdout, "Who I am? My ID is %i\n", (int) getpid()); }
spring/Lect2>./2 Before RECREATION 6169 I'm not yet dead! My ID is 6169 Who I am? My ID is 6170 I'm not yet dead! My ID is 6169 Who I am? My ID is 6170 spring/Lect2>./2 Before RECREATION 6154 I'm not yet dead! My ID is 6154 Who I am? My ID is 6155 I'm not yet dead! My ID is 6154 С точки зрения планировщика дочерний и родительский процессы независимы:
#include int main(){ pid_t child_pid, parent_pid ; double s=0.0;; child_pid=fork(); if(child_pid!=0){ s+=3.14; fprintf(stdout, "CHILD: %i s=%g &s=%u\n", (int) getpid(),s,&s); } else{ s+=2.72; fprintf(stdout, "PARENT: %i s=%g &s=%u\n", (int) getpid(),s, &s); } return 0; }
PARENT: 5404 s=2.72 &s= CHILD: 5403 s=3.14 &s= При создании процесса с помощью системного вызова fork() копируется адресное пространство, - переменная s имеет один и тот же адрес. Однако отображение на физическую память для родительского и дочернего процесса различно, - значения переменной s различны. Output:
#include int main(){ pid_t child_pid; pid_t parent_pid; double s=0.0;; FILE* fp; child_pid=fork(); fp=fopen("test.dat","a+");
PARENT: 5450 s=2.72 &s= fp= CHILD: 5449 s=3.14 &s= fp= if(child_pid!=0){ s+=3.14; fprintf(fp, "CHILD: %i s=%g &s=%u fp=%u\n", (int) getpid(), s, &s, fp); } else{ s+=2.72; fprintf(fp, "PARENT: %i s=%g &s=%u fp=%u\n",(int) getpid(), s, &s,fp); } fclose(fp); return 0; } test.dat Дескрипторы файлов при копировании сохраняются.
#include int main(int argc, char* argv[]){ fprintf(stdout, "Before child process creating: PARENT ID = %i\n", (int) getpid()); execvp(argv[1], argv); //execvp("ls", argv); fprintf(stdout, "Everything is ignored!\n"); return 0; } Создание процессов с помощью семейства системных вызовов exec*:
./6ex Before child process creating: PARENT ID = c 2 2.c 2.dat 3 3.c 4 4.c 5 5.c 6 6.c 6ex 6ex.c test.dat./6ex -l *.dat Before child process creating: PARENT ID = rw-r--r-- 1 ewgenij users :34 2.dat -rw-r--r-- 1 ewgenij users :37 test.dat./6ex./5 Before child process creating: PARENT ID = 5923 CHILD: 5923 s=3.14 &s= PARENT: 5924 s=2.72 &s= Output:
#include int main(int argc, char* argv[]){ pid_t child_pid; child_pid=fork(); if( child_pid==0) execvp("ls", argv); fprintf(stdout,"The main program is yet running!\n"); return 0; } Совместное использование fork и execvp:
-l *.png The main program is yet running! -rw-r--r-- 1 ewgenij users :27 exec1.png Родительский процесс продолжает существовать и активен:
#include void oldman(){ fprintf(stdout, "I'm not yet dead! My ID is %i\n", (int) getpid()); } void recreation(){ fprintf(stdout, "Who I am? My ID is %i\n", (int) getpid()); } int main(){ pid_t child_pid, parent_pid; int i=0; fprintf(stdout, "Before RECREATION %i\n", parent_pid=(int) getpid()); child_pid=fork();
I'm not yet dead! My ID is 6526 Who I am? My ID is 6527 I'm not yet dead! My ID is 6526 while(i++
Интерфейс системных вызовов MS Windows Win32 Особенности реализации языка С компании Microsot (компилятор cl). Некоторые типы данных, поддерживаемые Microsoft Windows: DWORDtypedef unsigned long DWORD BOOLtypedef int BOOL; BYTEtypedef unsigned char BYTE; PVOIDtypedef void *PVOID; HANDLEtypedef PVOID HANDLE;
Чтобы обеспечить поддержку типов Microsoft Windows в программе, необходимо включить в нее заголовочный файл windows.h. Этот файл также содержит объявления функций интерфейса системных вызовов MS Windows Win32 API. Пример объявления функции: BOOL GetComputerName( LPTSTR lpBuffer; LPDWORD nSize; ); LPSTRtypedef char *LPSTR LPDWORDtypedef WORD *LPDWORD
#include int main(){ char Buffer[MAX_COMPUTERNAME_LENGTH+1];//[5]; int size=sizeof(Buffer); if( !GetComputerName((LPTSTR)Buffer, (LPDWORD)&size) ){ printf("System error code: %i\n",GetLastError()); return -1; } fprintf(stdout,"The computer name is %s\n",Buffer); return 0; }
110….……………………………………………………1 11 ERROR_BUFFER_OVERFLOW 112………………………………………………………. C:\2011-spring\Лекции\Лекция2\Лаб2c>1 The computer name is EWGENIJ-PC C:\2011-spring\Лекции\Лекция2\Лаб2c>1 System error code: 111 Запись в таблице System Error Codes: Аварийный выход (при задании размера буфера равным 5): Нормальное выполнение:
Упражнение: Программно определить пути к системному каталогу Windows и каталогу временных файлов Windows, используя следующие функции Win32 API: UINT GetWindowsDirectory( LPTSTR lpBuffer, UINT uSize ); DWORD GetTempPath( DWORD nBufferLength, LPSTR lpBuffer ); Замечание. Примеры венгерской нотации: ПрефиксТип данных uбеззнаковое целое lpдальний указатель (long pointer) (атавизм) szстрока, заканчивающаяся нулевым байтом (c- строка) nкороткое целое
Создание процессов в Windows. Замечание (использование семейств функций exec и spawn в Windows-приложениях. ): В заголовочном файле process.h содержаться макросы и объявления функций exec*, spawn*, которые могут использоваться для создания процессов. Стандарт ANSI/ISO C не включает process.h, но этот заголовочный файл и библиотеки времени исполнения, содержащие реализации соответствующих функций присутстсвуют на многих платформах. В частности, эти функции поддерживаются компиляторами компаний Borland и Microsoft на платформах MS DOS и Windows 3.1. В качестве расширения process.h содержится в стандарте POSIX ( Portable Operating System Interface for Unix ). Замечание: порты Cygwin и Interix
Примеры использования exec*: #include void main(int argc, char* argv[]){ if(argc
#include void main(){ char* argv[]={ "cmd", "/C", "dir", NULL }; _execvp(argv[0],argv); printf( "\nProcess was not execed." ); exit( 0 ); }
void main(){ char* argv[]={ "notepad", NULL }; //_spawnvp(_P_OVERLAY, argv[0],argv); _spawnvp(_P_NOWAIT, argv[0],argv); printf( "\nParent process is yet running." ); exit( 0 ); }
#include int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ char* argv[]={ "notepad", NULL }; //_spawnvp(_P_OVERLAY, argv[0],argv); _spawnvp(_P_NOWAIT, argv[0],argv); MessageBox(NULL, "Parent process is yet running., "Message",MB_OK); return 0; } winspawn.c
LPSTRtypedef char *LPSTR HANDLEtypedef PVOID HANDLE HINSTANCEtypedef HANDLE HINSTANCE hInstance – дескриптор текущего экземпляра приложения. hPrevInstance – дескриптор предыдущего экземпляра приложения (рудимент, всегда NULL). lpCmdLine – параметры командной строки. nCmdShow – константа, задающая вид окна. #define WINAPI __stdcall /*соглашение для вызова функций Win32 API*/
Упражнение: Модифицируйте программу winspawn.c так, чтобы процесс создавался с задержкой в 5 секунд (или 5 часов). Можно использовать функцию Win32 API: typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME, *LPSYSTEMTIME; VOID GetSystemTime( LPSYSTEMTIME lpSystemTime );