Всем доброго времени суток. Задача такая: Заставьте консольный процесс запустить несколько своих копий (и далее рекурсивно). Убедитесь, что порождение процессов не будет бесконечным (остановитесь на 4 уровнях максимум) Вопрос состоит в следующем: как мне именно остановить рекурсию после создания 4 процесса? Подскажите пожалуйста, жду ответов, заранее спасибо.
Решил попробывать с семафором. Идея показалась простой, а вот реализация у меня вызывает затруднения(( Чесно скажу в программировании новичок, а здать лабу надо. Исправте или подскажите на мои ошибки в коде. Вроде - бы все должно быть просто: создаю семафор с макс. числом обращений равное 4, потом создаю процесс и увеличиваю счетчик на 1. Но на самом деле запускается куча процессов и система виснет int main(int argc, char **argv) { DWORD dwWaitResult; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; si.lpTitle = "Daughter process"; si.dwFlags = STARTF_USEFILLATTRIBUTE|STARTF_USEPOSITION|STARTF_USESIZE; si.dwXSize = 800; si.dwYSize = 300; HANDLE hSem = CreateSemaphore(NULL, 0, 4, "MySem"); CreateProcess(argv[0], NULL, NULL, NULL, TRUE,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); ReleaseSemaphore(hSem,1,NULL); getchar(); return 0; }
Эм...ну подскажите хоть кто-нибудь? В чем ошибка? Код (Text): int main(int argc, char **argv) { DWORD dwWaitResult; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; si.lpTitle = "Daughter process"; si.dwFlags = STARTF_USEFILLATTRIBUTE|STARTF_USEPOSITION|STARTF_USESIZE; si.dwXSize = 800; si.dwYSize = 300; HANDLE hSem = CreateSemaphore(NULL, 1, 4, "MySem"); OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE, "MySem"); cout<<"Proverka sostoyania semafora\n"; WaitForSingleObject(hSem, INFINITE); cout<<"polu4en dostup\n"; CreateProcess(argv[0], NULL, NULL, NULL, TRUE,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); Sleep(2000); ReleaseSemaphore(hSem,1,NULL); getchar(); return 0; }
wild89 Не теряй: set i=0 && set s="set /a i=i+1 && if ^!i^! NEQ 4 start cmd /k %s%" && cmd /k !s! Лол.
Код (Text): #include <windows.h> #include <stdio.h> #include <tchar.h> #define NUM_LEVELS 4 #define NUM_CHILDS 2 int _tmain(int argc, const TCHAR *argv[]) { SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; HANDLE hSem = CreateSemaphore(&sa, NUM_LEVELS, NUM_LEVELS, TEXT("MySym")); if (WaitForSingleObject(hSem, 0) == WAIT_OBJECT_0) { PROCESS_INFORMATION pi = {0}; STARTUPINFO si; TCHAR szModuleName[MAX_PATH]; HANDLE ahProcesses[NUM_CHILDS]; HANDLE ahThreads[NUM_CHILDS]; unsigned i; GetModuleFileName(NULL, szModuleName, MAX_PATH); GetStartupInfo(&si); _tprintf(__T("Creating childrens...\n")); Sleep(2000); for (i = 0; i < NUM_CHILDS; ++i) { CreateProcess(szModuleName, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); ahProcesses[i] = pi.hProcess; ahThreads[i] = pi.hThread; } _tprintf(__T("Done.\n")); WaitForMultipleObjects(NUM_CHILDS, ahProcesses, TRUE, INFINITE); for (i = 0; i < NUM_CHILDS; ++i) { CloseHandle(ahThreads[i]); CloseHandle(ahProcesses[i]); } } Sleep(INFINITE); return 0; } Показана лишь идея, не могу сейчас думать, как сделать заполнение уровней целиком, чтобы получилось полное дерево. Оставим это дело ТС.
l3Ta0n Попробывал твой совет, всеравно не получается. Код (Text): int main(int argc, char **argv) { HANDLE hSem; DWORD dwWaitResult; HANDLE hMutex; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; si.lpTitle = "Daughter process"; si.dwFlags = STARTF_USEFILLATTRIBUTE|STARTF_USEPOSITION|STARTF_USESIZE; si.dwXSize = 800; si.dwYSize = 300; hSem = OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE, "MySem"); if(!hSem) { hSem = CreateSemaphore(NULL,1, 4, "MySem"); //ReleaseSemaphore(hSem,1,NULL); } else{ WaitForSingleObject(hSem, INFINITE); ReleaseSemaphore(hSem,1,NULL); } Sleep(2000); CreateProcess(argv[0], NULL, NULL, NULL, TRUE,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); getchar(); return 0; }
Всё оказалось проще чем я ожидал. функция ReleaseSemaphore возвращает количство запущенных процессов)) Код (Text): #include "windows.h" #include <iostream> using namespace std; int main(int argc, char **argv) { DWORD dwWaitResult; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; si.lpTitle = "Daughter process"; si.dwFlags = STARTF_USEFILLATTRIBUTE|STARTF_USEPOSITION|STARTF_USESIZE; si.dwXSize = 800; si.dwYSize = 300; int MaxApplicationCount =4; HANDLE ApplicationCountSemaphore = CreateSemaphore(NULL, 0, MaxApplicationCount, "MySem"); if(ApplicationCountSemaphore == NULL) { } int GlobalApplicationCount; ReleaseSemaphore(ApplicationCountSemaphore, 1, (LPLONG)&GlobalApplicationCount); cout<<GlobalApplicationCount<<"\n"; if(GlobalApplicationCount<MaxApplicationCount){ cout<<GlobalApplicationCount<<"\n"; Sleep(2000); CreateProcess(argv[0], NULL, NULL, NULL, TRUE,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); } cout<<"Finished"; getchar(); return 0; } Удачи!
KeSqueer А нечего было идти на поводу и делать реализацию с семафором. Рекурсия она на то и рекурсия, чтобы работать с локальными для каждой инстанции данными, а не с глобальными объектами. Хотя, если я правильно понял, "дерево" должно быть унарным. В любом случае городить огород с глобальными объектами ИМХО сложнее, чем передать параметр в процесс в качестве уровня вложенности вызова. 1) Простейший способ это сделать — использовать какой-нибудь бесполезный параметр из STARTUPINFO (указанные элементы этой структуры будут отображены в PEB дочернего процесса): например, hStdError (при этом не забыть указать валидные hStdInput/hStdOutput). 2) Ещё один простой способ — инкрементировать переменную окружения через GetEnvironmentVariable/SetEnvironmentVariable. 3) Также работоспособный вариант — передавать параметр прямо через командную строку.
l_inc Если я правильно понял, ТС не понял условия задачи, и дерево должно быть полным: Заставьте консольный процесс запустить несколько своих копий (и далее рекурсивно). Убедитесь, что порождение процессов не будет бесконечным (остановитесь на 4 уровнях максимум) 1), 2) и 3) - IMHO, не кошерно. P.S. С каких пор в Российских ВУЗах преподают программирование под Win32?
KeSqueer Унарное дерево всегда полное. Мало того... оно ещё и всегда совершенное. Но да... наверное, Вы правы, и дерево должно быть как минимум бинарным. Ну так это тем более говорит в пользу того, что параметр глубины вложенности должен быть локальным для процесса. Ну 1) — понятно (хотя самый простой вариант): не для этих целей параметры там предназначены. 3) — понятно... мало ли какую командную строку пользователь захочет передать. А чем уже 2) не кошерно?
l_inc Ну, да, это я подразумевал... Чем 2) лучше способа с семафорами? Где уровень вложенности определяется по результату ReleaseSemaphore. P.S. Ну вообще-то 2) просто попал под раздачу. Раз уж спорить, то основательно
KeSqueer Видимо тем, что уровень вложенности не определяется по результату ReleaseSemaphore (максимум - число живых процессов). Как раз в силу глобальности семафора.
Но все же можно с помощью несложный арифметических действий получить из результата ReleaseSemaphore уровень.