Рекурсивное создание процесса

Тема в разделе "WASM.WIN32", создана пользователем wild89, 27 мар 2010.

  1. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    тогда надо передавать уровень вложенности как параметр командной строки
     
  2. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Передавайте параметры всякие через именованную секцию.
     
  3. l3Ta0n

    l3Ta0n New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2009
    Сообщения:
    45
    Посмотрите на пост мой там всё работает. И через семафор реально реализовать рекурси.
     
  4. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    l3Ta0n
    Не знаю, у меня твой код создает кучу процессов.
    Вот что получилось у меня:
    Код (Text):
    1. #define PROCESS_COUNT 4
    2.  
    3. int main(int argc, char **argv)
    4. {
    5.  
    6.   DWORD dwWaitResult;
    7.   STARTUPINFO si = { sizeof(si) };
    8.   PROCESS_INFORMATION pi;
    9.  
    10.   si.lpTitle        = "Daughter process";
    11.   si.dwFlags        = STARTF_USEFILLATTRIBUTE|STARTF_USEPOSITION|STARTF_USESIZE;
    12.   si.dwXSize        = 800;
    13.   si.dwYSize        = 300;
    14.  
    15.  
    16. HANDLE hSem = CreateSemaphore(NULL, PROCESS_COUNT, PROCESS_COUNT, "MySem");
    17.  
    18. OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE, "MySem");
    19.  
    20. cout<<"Proverka sostoyania semafora\n";
    21.  
    22. if(WAIT_OBJECT_0 == WaitForSingleObject(hSem, 0)) {
    23.  
    24.     cout<<"polu4en dostup\n";
    25.  
    26.     CreateProcess(argv[0], NULL, NULL, NULL,    TRUE,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
    27.      Sleep(2000);
    28. } else {
    29.     cout<<"dostupa net\n";
    30. }
    31.  
    32. getchar();
    33.  
    34. CloseHandle(hSem);
    35.  
    36. return 0;
    37. }
     
  5. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    KeSqueer
    Так в том то и дело, что достоверно это сделать нельзя. :) Race condition, так сказать. Например, одна ветка дерева может целиком отпасть ещё до того, как другая успеет запустить своих самых дальних родственников. И как предлагаете родственникам определить, что они самые дальние?
    Clerk
    Не получится. Параметры будут нелокальными.
    l3Ta0n
    В Вашем посте унарное дерево. KeSqueer вполне логично предположил, что дерево должно быть минимум бинарным. Одними семафорами здесь не обойтись.
    wild89
    Очень неудачное решение.
    1) OpenSemaphore не имеет смысла, но просто вызывает потерю хэндла.
    2) Sleep (2000) вместо ожидания на хэндле процесса — очень плохо.
    3) Хэндлы дочернего процесса и потока не закрываются.
    4) Нет возможности расширения для неунарных деревьев.

    В общем в качестве основы вот простой пример крайне некошерного (но рабочего) решения для тернарного дерева на основе переопределения хэндла hStdError:
    Код (Text):
    1. #define NUM_CHILDREN 3
    2. int main()
    3. {
    4.     STARTUPINFO sii = {0};
    5.     PROCESS_INFORMATION pii;
    6.     DWORD depth = (DWORD)GetStdHandle(STD_ERROR_HANDLE);
    7.     if (depth >= 4)
    8.         depth = 0;                      // слабое место, хоть и будет работать
    9.     char indent[4] = {0};
    10.     printf("%sI'm a child number %d\n",memset(indent,'\t',depth),depth);
    11.     if (depth < 3)
    12.     {
    13.         sii.cb = sizeof(sii);
    14.         sii.dwFlags = STARTF_USESTDHANDLES;
    15.         sii.hStdError = (HANDLE)(depth+1);
    16.         sii.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // слабое место, хоть и будет работать
    17.         sii.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);   // слабое место, хоть и будет работать.
    18.         HANDLE proc[NUM_CHILDREN];
    19.         TCHAR szModuleName[MAX_PATH];
    20.         GetModuleFileName(NULL, szModuleName, MAX_PATH);
    21.         for (int par = 0; par < NUM_CHILDREN; par++)
    22.         {
    23.             CreateProcess(szModuleName,NULL,NULL,NULL,false,0,NULL,NULL,&sii,&pii);
    24.             CloseHandle(pii.hThread);
    25.             proc[par]=pii.hProcess;
    26.         }
    27.         WaitForMultipleObjects(NUM_CHILDREN,proc,true,INFINITE);
    28.         for (int par = 0; par < NUM_CHILDREN; par++)
    29.             CloseHandle(proc[par]);
    30.     }
    31.     return 1;
    32. }
    Рекомендую минимальными усилиями переделать для варианта с переменными окружения.
     
  6. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    А как можно перенаправить консольный вывод в файл? (Кроме параметра >> в cmd)
    И заставить все процессы, наследовать дескриптор этого файла?
     
  7. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    wild89
    Это часть задания? Потому что иначе зачем?
    Делается это просто:
    1) открыть файл, назначив его хэндл наследуемым (параметр lpSecurityAttributes).
    2) при запуске дочернего процесса указать наследовать наследуемые хэндлы дочерним процессом (параметр bInheritHandles).
    3) там же (т.е. при запуске дочернего процесса) указать в структуре lpStartupInfo хэндл открытого файла в поле hStdOutput.
    Т.о. стандартный хэндл консольного вывода будет переопределён в дочернем процессе.
     
  8. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    Да это задание, спасибо, буду пытаться.
     
  9. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    Посмотрите, что я делаю не так?^((( Чувствую себя полный ламером.
    Первый пункт:
    Код (Text):
    1. LPSECURITY_ATTRIBUTES sa = NULL;
    2. HANDLE f;
    3. f = CreateFile("1.txt",GENERIC_WRITE,FILE_SHARE_WRITE,sa/*назначить его хэндл наследуемым*/,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    Второй пункт:
    Код (Text):
    1. CreateProcess(argv[0], NULL, NULL, NULL, TRUE/*наследовать наследуемые хэндлы дочерним процессом*/,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
    Третий пункт я не понял...можно по подробней?
     
  10. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    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).
     
  11. l3Ta0n

    l3Ta0n New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2009
    Сообщения:
    45
    l_inc
    не линейное, а процесс експлорер выдет их в виде дерева.
    Один дочерний второго, а третий в свою очередь от второго.
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    l3Ta0n
    В каком смысле "не линейное"? Разумеется, Process Explorer выведет его в виде дерева. Только унарного. Т.е. у каждого процесса не более одного дочернего процесса. Согласно цитате, приведенной KeSqueer, каждый процесс должен запустить несколько дочерних.
     
  13. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    Не могу понять, что значит "Только в hStdOutput нужно выставить не GetStdHandle(STD_OUTPUT_HANDLE), а хэндл файла с наследуемым хэндлом (из пункта 1)."

    Код (Text):
    1. _SECURITY_ATTRIBUTES sa;
    2. sa.bInheritHandle= TRUE;
    3. sa.nLength=sizeof(sa);
    4.  
    5. HANDLE f;
    6. f = CreateFile("1.txt",GENERIC_WRITE,FILE_SHARE_WRITE,&sa/*назначить его хэндл наследуемым*/,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    7.  
    8.  
    9. si.hStdOutput = f; // Что здесь задавать? Мне кажется явно не f, т.к вывод не идет не на консоль ни в файл.
     
  14. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    wild89
    Именно f. Но Вы проверили, что возвращает CreateFile? Кофейная гуща настаивает, что в поле lpSecurityDescriptor находится мусор из стека, в результате чего вызов CreateFile проваливается.
     
  15. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    l_inc
    Вы абсолютно правы, отладил построчно - вызов CreateFile проваливается.
    Что нужно задать в поле sa.lpSecurityDescriptor ?
     
  16. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    wild89
    Если не хотите никаких наворотов в дескриптор безопасности хэндла, то NULL вполне сойдёт. :)
     
  17. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    P.S. Не забывайте и в других структурах (типа si) инициализировать нулями критичные к этому поля (лучше сразу объявлять структуру в духе STARTUPINFO sii = {0}, как в посте 25 :)). Иначе могут последовать непредсказуемые последствия.
     
  18. wild89

    wild89 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    15
    l_inc
    Вроде-бы все должно работать, но файл хоть и создатется - остается пустым....в чем может быть проблема?

    Код (Text):
    1. #include <windows.h>
    2. #include <stdio.h>
    3. #include <tchar.h>
    4. #include <iostream>
    5.  
    6. using namespace std;
    7.  
    8. #define PROCESS_COUNT 4
    9.  
    10. int main(int argc, char **argv)
    11. {
    12.  
    13.   STARTUPINFO si = { 0 };
    14.   PROCESS_INFORMATION pi;
    15.  
    16.   _SECURITY_ATTRIBUTES sa; //
    17.  
    18.   sa.bInheritHandle= TRUE;
    19.   sa.nLength=sizeof(sa);
    20.   sa.lpSecurityDescriptor = NULL;
    21.  
    22. // создаем файл
    23.   HANDLE f;
    24.   f = CreateFile("C:\\1.txt",GENERIC_WRITE,FILE_SHARE_WRITE,&sa/*назначить его хэндл наследуемым*/,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    25.   si.cb             = sizeof(si);
    26.   si.lpReserved     = NULL;
    27.   si.lpDesktop      = NULL;
    28.   si.lpTitle        = "my process";
    29.   si.dwFlags = STARTF_USESTDHANDLES;
    30.   si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);    // слабое место, хоть и будет работать
    31.   si.hStdOutput = f;// ПЕРЕНАПРАВЛЯЕМ ВЫВОД
    32.  
    33.  
    34. HANDLE hSem = CreateSemaphore(NULL, PROCESS_COUNT, PROCESS_COUNT, "MySem");
    35.  
    36. OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE, "MySem");
    37.  
    38. printf("Proverka sostoyania semafora\n");
    39.  
    40. if(WAIT_OBJECT_0 == WaitForSingleObject(hSem, 0)) {
    41.    CreateProcess(argv[0], NULL, NULL, NULL, TRUE/*наследовать наследуемые хэндлы дочерним процессом*/,CREATE_NEW_CONSOLE|NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
    42.    printf("polu4en dostup\n");
    43. } else {
    44.     printf("dostupa net\n");
    45. }
    46.  
    47. getchar();
    48. CloseHandle(f);
    49. CloseHandle(hSem);
    50. CloseHandle(pi.hProcess);
    51. CloseHandle(pi.hThread);
    52.  
    53. return 0;
    54. }
     
  19. mrcrown

    mrcrown Member

    Публикаций:
    0
    Регистрация:
    18 янв 2008
    Сообщения:
    227
    судя по докам если семафор уже создан то на криейт откроется предыдущий, а не создастся новый
     
  20. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    wild89
    Несмотря на то, что код всё ещё отвратительный, наследование хэндла вывода выполнено правильно и вывод в файл должен осуществляться (хоть и не совсем такой, каким Вы его ожидаете). Тем не менее CRT по какой-то причине избегает выполнять WriteFile в унаследованный хэндл.
    Посмотрел, как это делает cmd... Он также делает хэндл наследуемым и указывает флаг наследования в CreateProcess, но (!) при этом он не использует поле hStdOutput, заменяя его каким-то хитрым недокументированным атрибутом PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS в расширенной структуре STARTUPINFOEX.
    В общем самому интересно, почему CRT отказывается писать в файл. Может кто-нибудь другой объяснит... :)
    Проверял на Vista SP1 (на более ранних версиях STARTUPINFOEX не поддерживается). Какая у Вас ОС?