Требуется создать несколько процессов и сгруппировать их в «задание».
И в процессе выполнения у меня возникли некоторые вопросы...
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(si));
si.cb=sizeof(si);
//Создадим два процесса
CreateProcess
("D:\\WINDOWS\\Lab2.exe",NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
CreateProcess
("D:\\Program Files\\Borland\\Delphi7\\Bin\\delphi32.exe",NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa,sizeof(sa));
char str[10];
strcpy(str,"Job'\0'");
//Создадим задание
CreateJobObject(&sa,str);
//получим дескриптор объекта-задание
HANDLE hJ = OpenJobObject(JOB_OBJECT_ASSIGN_PROCESS,FALSE,str);
//в предыдущей строке 2-й параметр bInheritHandles - флаг наследования дескриптора...
//каково его назначение?
//Добавим процесс в задание
//AssignProcessToJobObject(hJ,???);
Ну, у меня вот так отработало:
#define JOB_ID "MyFirstJob\0"(то же самое можно сделать и с несколькими процессами)... Вроде Job создается, в аттаче - картинка, как это видно через ProcessExplorer от SysInternals...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
HANDLE hjob = CreateJobObject(NULL, JOB_ID);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(NULL, "notepad.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si,π);
AssignProcessToJobObject(hjob, pi.hProcess);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
HANDLE h[2];
h[0] = pi.hProcess;
h[1] = hjob;
DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw -WAIT_OBJECT_0) {
case 0:
// Процесс завершен
break;
case 1:
// Все время CPU, назначенное процессу, израсходовано
break;
}
CloseHandle(pi.hProcess);
CloseHandle(hjob);
}
#define JOB_ID "MyFirstJob\0"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
//....
DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw -WAIT_OBJECT_0) {
case 0:
// Процесс завершен
break;
case 1:
// Все время CPU, назначенное процессу, израсходовано
break;
}
}
А что ты хочешь делать с запущенными тобой процессами? Ну, запустила ты процесс. Добавила в JobObject, что дальше? Сразу удалить? Или сделать задержку, чтобы посмотреть, что оно запустилось, и потом удалить? С помощью WaitForSingleObject я жду завершения запущенного процесса, и потом удаляю пакет...
Ну, а в switch-е просто диагностика, по какой причине процесс завершился...
Попробовала переписать создание процесса и добавление его в "задание" на Visual C++...
Приложение запустилось, после нажатия на кнопку, в обработчике которой происходит создание процесса, приложение вылетело...(сообщение о произошедшем на прикреплённом рисунке)
Объясните пожалуйста, в чём я ошиблась?
...
HANDLE hjob = CreateJobObject(NULL, TEXT("LAB2"));
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(NULL, TEXT("notepad.exe"), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si,&pi); //здесь //и вылетает..
AssignProcessToJobObject(hjob, pi.hProcess);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
HANDLE h[2];
h[0] = pi.hProcess;
h[1] = hjob;
DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw -WAIT_OBJECT_0) {
case 0:
break;
case 1:
break;
}
CloseHandle(pi.hProcess);
CloseHandle(hjob);
...
Старая проблема... Вкратце: второй параметр функции CreateProcess должен быть типа LPCSTR, то есть, должен быть доступен как для чтения, так и для записи... Предыдущие версии (VC6 и ниже), да и Билдер (до 2007 включительно, в Билдере 2009 тоже начнутся проблемы) работают с CreateProcessA, которая хоть и получает константную строку, но в процессе работы конвертирует ее во внутренний юникодный буфер с помощью MultiByteToWideChar, и потом вызывает CreateProcessW, которая и создает процесс...
Когда же ты работаешь в VC2005+ (или Builder 2009), под вызовом CreateProcess подразумевается прямой вызов CreateProcessW, без промежуточных преобразований... Но ведь TEXT("notepad.exe") - это константа только для чтения, поэтому и возникает ошибка... Исправлять - так:
...
TCHAR lpProcName[]=TEXT("notepad.exe"); // создаем доступный для чтения _и записи_ буфер
CreateProcess(NULL, lpProcName, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, & si, & pi);
...
У меня такой вопрос: если я хочу создать несколько процессов (VC++ 2008 EE), мне нужно задействовать по нескольку структурных переменных типов STARTUPINFO и PROCESS_INFORMATION или это лишнее (с учётом того, что с созданными процессами нам потом работать - объединять в задание)?
Дублирование STARTUPINFO в любом случае лишнее... Попробовал в код из сообщения №2 добавить еще один процесс, не добавляя для него STARTUPINFO - процессы нормально добавляются (обрати внимание, в функции CreateProcess предпоследний параметр - IN, то есть, не возвращает ничего нового из функции, а вот последний - OUT, значит возвращает полезную информацию)...
Вот что у меня получилось..
Вылетает с ошибкой Run-Time Check Failure #2 - Stack around the variable 'h' was corrupted.
RECT Rect;
GetClientRect(hwnd,&Rect);
TCHAR lpProcName[]=TEXT("");
TCHAR lpProcName1[]=TEXT("");
TCHAR lpProcName2[]=TEXT("");
HANDLE hjob = CreateJobObject(NULL, TEXT("LAB2"));
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi,pi1,pi2;
GetWindowText(hEditProc,(LPWSTR)lpProcName,30);
GetWindowText(hEditProc1,(LPWSTR)lpProcName1,30);
GetWindowText(hEditProc2,(LPWSTR)lpProcName2,30);
CreateProcess(NULL, lpProcName, NULL, NULL, FALSE,CREATE_SUSPENDED, NULL, NULL, & si, & pi);
CreateProcess(NULL, lpProcName1, NULL, NULL, FALSE,CREATE_SUSPENDED, NULL, NULL, & si, & pi1);
CreateProcess(NULL, lpProcName2, NULL, NULL, FALSE,CREATE_SUSPENDED, NULL, NULL, & si, & pi2);
AssignProcessToJobObject(hjob, pi.hProcess);
AssignProcessToJobObject(hjob, pi1.hProcess);
AssignProcessToJobObject(hjob, pi2.hProcess);
ResumeThread(pi.hThread);
ResumeThread(pi1.hThread);
ResumeThread(pi2.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi1.hThread);
CloseHandle(pi2.hThread);
HANDLE h[3];
h[0] = pi.hProcess;
h[1] = pi1.hProcess;
h[2] = pi2.hProcess;
h[3] = hjob;
DWORD dw = WaitForMultipleObjects(3, h, FALSE, INFINITE);
switch (dw -WAIT_OBJECT_0) {
case 0:
//EdProc->Text="Процесс завершен"/;
break;
case 1:
//EdProc->Text="Все время CPU, назначенное процессу, израсходовано";
break;
}
CloseHandle(pi.hProcess);
CloseHandle(pi1.hProcess);
CloseHandle(pi2.hProcess);
CloseHandle(hjob);
....
HANDLE h[4];должно работать...
h[0] = pi.hProcess;
h[1] = pi1.hProcess;
h[2] = pi2.hProcess;
h[3] = hjob;
DWORD dw = WaitForMultipleObjects(4, h, FALSE, INFINITE);
Хочу установить ограничения для всех процессов в созданном ранее задании на класс приоритета...Скажите пожалуйста, а какие это классы? И устанавливать нужно, используя функцию SetInformationJobObject() или нет?
// создаем объект ядра "задание"(фрагмент программы - из книги Дж. Рихтера "Создание эффективных Win32 приложений", глава 5)
HANDLE hjob = CreateJobObject(NULL, NULL);
// вводим ограничения для процессов в задании
// сначала определяем некоторые базовые ограничения
JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };
// процесс всегда выполняется с классом приоритета idle
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
// задание не может использовать более одной секунды процессорного времени
jobli.PerJobUserTimeLimit.QuadPart = 10000000;
// 1 секунда, выраженная в 100-наносекундных интервалах
// два ограничения, которые я налагаю на задание (процесс)
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS | JOB_OBJECT_LIMIT_JOB_TIME;
SetInformationJobObject(hjob, JobObjectBasicLimitInformation, &jobli, sizeof(jobli));
// теперь вводим некоторые ограничения по пользовательскому интерфейсу
JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;
jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;
// процесс не имеет права останавливать систему
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
// процесс не имеет права обращаться к USER-объектам в системе
// (например, к другим окнам)
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
SetInformationJobObject(hjob, JobObjectBasicUIRestrictions,
&jobuir, sizeof(jobuir));
// Порождаем процесс, который будет размещен в задании.
// Ну, дальше ты знаешь, что делать...
Спасибо большое!)
TCHAR lpProcName[256]=TEXT("");
GetWindowText(hEditPriority,(LPWSTR)lpProcName,50);
if (lpProcName==TEXT("IDLE"))
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
if (lpProcName==TEXT("NORMAL"))
jobli.PriorityClass = NORMAL_PRIORITY_CLASS;
if (lpProcName==TEXT("BELOW_NORMAL"))
jobli.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
if (lpProcName==TEXT("ABOVE_NORMAL"))
jobli.PriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
if(!wcscmp(lpProcName, L"IDLE")) {В Билдере по-крайней мере работает...
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
}
Теперь пытаюсь вывести информацию о имеющемся задании...
Вот такая ошибка:
1>c:\study\3 kyrs\os\lab3\lab3\main.cpp(301) : error C2440: 'initializing' : cannot convert from 'void *' to 'PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION'
Объясните пожалуйста, как устранить эту ошибку?
//...
wchar_t pszStrPID[256];
DWORD size = sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION);
PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION pjbai= _alloca(size); //(301)
QueryInformationJobObject(hjob,JobObjectBasicAccountingInformation,pjbai,size,&size);
HWND hActivePr=CreateWindow(TEXT("STATIC"),NULL,WS_CHILD|WS_VISIBLE|SS_LEFT,
(int)(Rect.left+135),(int)(Rect.top+120),(int)(Rect.right- Rect.left-700),20,hwnd,NULL,hInstance,NULL);
wsprintf(pszStrPID,_T("%d"), pjbai->ActiveProcesses);
SendMessage(hActivePr,WM_SETTEXT, 0, (LPARAM)(LPCSTR)pszStrPID);
PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION pjbai =(Обрати внимание на предупреждение, что _alloca() не рекомендавана к использованию; есть более безопасная версия: _malloca()...)
(PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION)_alloca(size);
Ранее я устанавливала приоритет..:
JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };
// процесс всегда выполняется с классом приоритета ...
GetWindowText(hEditPriority,(LPWSTR)lpProcName,50);
if(!wcscmp(lpProcName, L"IDLE"))
{
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("IDLE"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
if(!wcscmp(lpProcName, L"NORMAL"))
{
jobli.PriorityClass = NORMAL_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("NORMAL"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
if(!wcscmp(lpProcName, L"BELOW_NORMAL"))
{
jobli.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("BELOW_NORMAL"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
if(!wcscmp(lpProcName, L"ABOVE_NORMAL"))
{
jobli.PriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("ABOVE_NORMAL"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
PJOBOBJECT_BASIC_LIMIT_INFORMATION pjbli=(PJOBOBJECT_BASIC_LIMIT_INFORMATION)_malloca(size);
QueryInformationJobObject(hjob,JobObjectBasicLimitInformation,pjbli,size,&size);
HWND hPriority=CreateWindow(TEXT("STATIC"),NULL,WS_CHILD|WS_VISIBLE|SS_LEFT,
(int)(Rect.left+500),(int)(Rect.top+120),(int)(Rect.right- Rect.left-700),20,hwnd,NULL,hInstance,NULL);
wsprintf(pszStrPID,_T("%d"), pjbli->PriorityClass);
SendMessage(hPriority,WM_SETTEXT, 0, (LPARAM)(LPCSTR)pszStrPID);
Что показывает ProcessExplorer? Установились твои приоритеты для JobObject?
Вот, смотри:
(то, что выделено слева возвращается твоим методом). Устанавливался IDLE_PRIORITY_CLASS...
Вроде класс введённый (IDLE) установился...
А при получении информации вижу 32..
Эскизы прикрепленных изображений
P.S. Возможно, SetInformationJobObject() или QueryInformationJobObject() возвращают признак ошибки (если возвращается 0, значит функция не отработала), тогда придется получить номер ошибки через GetLastError() и смотреть, в чем причина...
ERROR_INVALID_PARAMETER? Показывай вызов функции и заполнение всех ее параметров... Один из них заполнен неправильно...
hjob = CreateJobObject(NULL, TEXT("LAB2"));
// вводим ограничения для процессов в задании
// сначала определяем некоторые базовые ограничения
JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };
// процесс всегда выполняется с классом приоритета ...
GetWindowText(hEditPriority,(LPWSTR)lpProcName,50);
if(!wcscmp(lpProcName, L"IDLE"))
{
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("IDLE"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
if(!wcscmp(lpProcName, L"NORMAL"))
{
jobli.PriorityClass = NORMAL_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("NORMAL"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
if(!wcscmp(lpProcName, L"BELOW_NORMAL"))
{
jobli.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("BELOW_NORMAL"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
if(!wcscmp(lpProcName, L"ABOVE_NORMAL"))
{
jobli.PriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
MessageBox(hWndMain,TEXT("ABOVE_NORMAL"),TEXT("Class of Priority:"),MB_ICONINFORMATION);
}
// задание не может использовать более одной секунды процессорного времени
//jobli.PerJobUserTimeLimit.QuadPart = 10000000;
// 1 секунда, выраженная в 100-наносекундных интервалах
// два ограничения, которые я налагаю на задание (процесс)
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS | JOB_OBJECT_LIMIT_JOB_TIME;
DWORD fl=0;
if (SetInformationJobObject(hjob, JobObjectBasicLimitInformation, &jobli, sizeof(jobli))==0)
fl=GetLastError();
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS | JOB_OBJECT_LIMIT_JOB_TIME;
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS;