l3Ta0n Не знаю, у меня твой код создает кучу процессов. Вот что получилось у меня: Код (Text): #define PROCESS_COUNT 4 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, PROCESS_COUNT, PROCESS_COUNT, "MySem"); OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE, "MySem"); cout<<"Proverka sostoyania semafora\n"; if(WAIT_OBJECT_0 == WaitForSingleObject(hSem, 0)) { cout<<"polu4en dostup\n"; CreateProcess(argv[0], NULL, NULL, NULL, TRUE,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); Sleep(2000); } else { cout<<"dostupa net\n"; } getchar(); CloseHandle(hSem); return 0; }
KeSqueer Так в том то и дело, что достоверно это сделать нельзя. Race condition, так сказать. Например, одна ветка дерева может целиком отпасть ещё до того, как другая успеет запустить своих самых дальних родственников. И как предлагаете родственникам определить, что они самые дальние? Clerk Не получится. Параметры будут нелокальными. l3Ta0n В Вашем посте унарное дерево. KeSqueer вполне логично предположил, что дерево должно быть минимум бинарным. Одними семафорами здесь не обойтись. wild89 Очень неудачное решение. 1) OpenSemaphore не имеет смысла, но просто вызывает потерю хэндла. 2) Sleep (2000) вместо ожидания на хэндле процесса — очень плохо. 3) Хэндлы дочернего процесса и потока не закрываются. 4) Нет возможности расширения для неунарных деревьев. В общем в качестве основы вот простой пример крайне некошерного (но рабочего) решения для тернарного дерева на основе переопределения хэндла hStdError: Код (Text): #define NUM_CHILDREN 3 int main() { STARTUPINFO sii = {0}; PROCESS_INFORMATION pii; DWORD depth = (DWORD)GetStdHandle(STD_ERROR_HANDLE); if (depth >= 4) depth = 0; // слабое место, хоть и будет работать char indent[4] = {0}; printf("%sI'm a child number %d\n",memset(indent,'\t',depth),depth); if (depth < 3) { sii.cb = sizeof(sii); sii.dwFlags = STARTF_USESTDHANDLES; sii.hStdError = (HANDLE)(depth+1); sii.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // слабое место, хоть и будет работать sii.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); // слабое место, хоть и будет работать. HANDLE proc[NUM_CHILDREN]; TCHAR szModuleName[MAX_PATH]; GetModuleFileName(NULL, szModuleName, MAX_PATH); for (int par = 0; par < NUM_CHILDREN; par++) { CreateProcess(szModuleName,NULL,NULL,NULL,false,0,NULL,NULL,&sii,&pii); CloseHandle(pii.hThread); proc[par]=pii.hProcess; } WaitForMultipleObjects(NUM_CHILDREN,proc,true,INFINITE); for (int par = 0; par < NUM_CHILDREN; par++) CloseHandle(proc[par]); } return 1; } Рекомендую минимальными усилиями переделать для варианта с переменными окружения.
А как можно перенаправить консольный вывод в файл? (Кроме параметра >> в cmd) И заставить все процессы, наследовать дескриптор этого файла?
wild89 Это часть задания? Потому что иначе зачем? Делается это просто: 1) открыть файл, назначив его хэндл наследуемым (параметр lpSecurityAttributes). 2) при запуске дочернего процесса указать наследовать наследуемые хэндлы дочерним процессом (параметр bInheritHandles). 3) там же (т.е. при запуске дочернего процесса) указать в структуре lpStartupInfo хэндл открытого файла в поле hStdOutput. Т.о. стандартный хэндл консольного вывода будет переопределён в дочернем процессе.
Посмотрите, что я делаю не так?^((( Чувствую себя полный ламером. Первый пункт: Код (Text): LPSECURITY_ATTRIBUTES sa = NULL; HANDLE f; f = CreateFile("1.txt",GENERIC_WRITE,FILE_SHARE_WRITE,sa/*назначить его хэндл наследуемым*/,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); Второй пункт: Код (Text): CreateProcess(argv[0], NULL, NULL, NULL, TRUE/*наследовать наследуемые хэндлы дочерним процессом*/,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); Третий пункт я не понял...можно по подробней?
wild89 1) Вы передаёте NULL в CreateFile в качестве lpSecurityAttributes. Это не есть "назначить хэндл наследуемым". Нужно передавать валидный указатель на структуру, в которой выставлено поле nLength в sizeof(LPSECURITY_ATTRIBUTES), а bInheritHandle в TRUE. 2) Флаги запуска выставлять не обязательно. А в Вашем случае CREATE_NEW_CONSOLE ещё и бессмысленна. 3) В CreateProcess Вы также передаёте указатель на структуру si. В посте 25 есть пример её заполнения. Только в hStdOutput нужно выставить не GetStdHandle(STD_OUTPUT_HANDLE), а хэндл файла с наследуемым хэндлом (из пункта 1).
l_inc не линейное, а процесс експлорер выдет их в виде дерева. Один дочерний второго, а третий в свою очередь от второго.
l3Ta0n В каком смысле "не линейное"? Разумеется, Process Explorer выведет его в виде дерева. Только унарного. Т.е. у каждого процесса не более одного дочернего процесса. Согласно цитате, приведенной KeSqueer, каждый процесс должен запустить несколько дочерних.
Не могу понять, что значит "Только в hStdOutput нужно выставить не GetStdHandle(STD_OUTPUT_HANDLE), а хэндл файла с наследуемым хэндлом (из пункта 1)." Код (Text): _SECURITY_ATTRIBUTES sa; sa.bInheritHandle= TRUE; sa.nLength=sizeof(sa); HANDLE f; f = CreateFile("1.txt",GENERIC_WRITE,FILE_SHARE_WRITE,&sa/*назначить его хэндл наследуемым*/,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); si.hStdOutput = f; // Что здесь задавать? Мне кажется явно не f, т.к вывод не идет не на консоль ни в файл.
wild89 Именно f. Но Вы проверили, что возвращает CreateFile? Кофейная гуща настаивает, что в поле lpSecurityDescriptor находится мусор из стека, в результате чего вызов CreateFile проваливается.
l_inc Вы абсолютно правы, отладил построчно - вызов CreateFile проваливается. Что нужно задать в поле sa.lpSecurityDescriptor ?
P.S. Не забывайте и в других структурах (типа si) инициализировать нулями критичные к этому поля (лучше сразу объявлять структуру в духе STARTUPINFO sii = {0}, как в посте 25 ). Иначе могут последовать непредсказуемые последствия.
l_inc Вроде-бы все должно работать, но файл хоть и создатется - остается пустым....в чем может быть проблема? Код (Text): #include <windows.h> #include <stdio.h> #include <tchar.h> #include <iostream> using namespace std; #define PROCESS_COUNT 4 int main(int argc, char **argv) { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi; _SECURITY_ATTRIBUTES sa; // sa.bInheritHandle= TRUE; sa.nLength=sizeof(sa); sa.lpSecurityDescriptor = NULL; // создаем файл HANDLE f; f = CreateFile("C:\\1.txt",GENERIC_WRITE,FILE_SHARE_WRITE,&sa/*назначить его хэндл наследуемым*/,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); si.cb = sizeof(si); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = "my process"; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // слабое место, хоть и будет работать si.hStdOutput = f;// ПЕРЕНАПРАВЛЯЕМ ВЫВОД HANDLE hSem = CreateSemaphore(NULL, PROCESS_COUNT, PROCESS_COUNT, "MySem"); OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE, "MySem"); printf("Proverka sostoyania semafora\n"); if(WAIT_OBJECT_0 == WaitForSingleObject(hSem, 0)) { CreateProcess(argv[0], NULL, NULL, NULL, TRUE/*наследовать наследуемые хэндлы дочерним процессом*/,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); printf("polu4en dostup\n"); } else { printf("dostupa net\n"); } getchar(); CloseHandle(f); CloseHandle(hSem); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0; }
wild89 Несмотря на то, что код всё ещё отвратительный, наследование хэндла вывода выполнено правильно и вывод в файл должен осуществляться (хоть и не совсем такой, каким Вы его ожидаете). Тем не менее CRT по какой-то причине избегает выполнять WriteFile в унаследованный хэндл. Посмотрел, как это делает cmd... Он также делает хэндл наследуемым и указывает флаг наследования в CreateProcess, но (!) при этом он не использует поле hStdOutput, заменяя его каким-то хитрым недокументированным атрибутом PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS в расширенной структуре STARTUPINFOEX. В общем самому интересно, почему CRT отказывается писать в файл. Может кто-нибудь другой объяснит... Проверял на Vista SP1 (на более ранних версиях STARTUPINFOEX не поддерживается). Какая у Вас ОС?