c++ - value - wait process in c




Qual é a coisa mais próxima que o windows tem para fork()? (8)

Eu acho que a pergunta diz tudo.

Eu quero garfo no windows. Qual é a operação mais semelhante e como eu a uso?


"assim que você quiser fazer o acesso ao arquivo ou o printf, então o io é recusado"

  • Você não pode ter seu bolo e comê-lo também ... em msvcrt.dll, o printf () é baseado na API do console, que por si só usa lpc para se comunicar com o subsistema do console (csrss.exe). A conexão com o csrss é iniciada na inicialização do processo, o que significa que qualquer processo que inicia sua execução "no meio" terá essa etapa ignorada. A menos que você tenha acesso ao código-fonte do sistema operacional, não há sentido em tentar se conectar ao csrss manualmente. Em vez disso, você deve criar seu próprio subsistema e, consequentemente, evitar as funções do console em aplicativos que usam fork ().

  • depois de ter implementado o seu próprio subsistema, não se esqueça de duplicar também todas as alças dos pais para o processo filho ;-)

"Além disso, você provavelmente não deve usar as funções Zw * a menos que esteja no modo kernel, você provavelmente deveria usar as funções Nt *."

  • Isso está incorreto. Quando acessado no modo de usuário, não há absolutamente nenhuma diferença entre Zw *** Nt ***; estes são meramente dois nomes exportados (ntdll.dll) diferentes que se referem ao mesmo endereço virtual (relativo).

ZwGetContextThread (NtCurrentThread (), & context);

  • obter o contexto do thread atual (em execução) chamando ZwGetContextThread está errado, provavelmente falhará e (devido à chamada extra do sistema) também não é o modo mais rápido de realizar a tarefa.

A semântica fork () é necessária quando o filho precisa acessar o estado real da memória do pai, a partir do momento em que o fork () é chamado. Eu tenho um pedaço de software que se baseia no mutex implícito de cópia de memória a partir do instante em que fork () é chamado, o que torna os threads impossíveis de usar. (Isso é emulado em modernas plataformas * nix via semântica de tabela de memória copy-on-write / update.)

O mais próximo que existe no Windows como um syscall é CreateProcess. O melhor que pode ser feito é que o pai congele todos os outros threads durante o tempo em que está copiando a memória para o espaço de memória do novo processo, depois descongele-os. Nem a classe Cygwin frok [sic] nem o código Scilab que Eric des Courtis postou faz o congelamento de threads, que eu posso ver.

Além disso, você provavelmente não deve usar as funções Zw * a menos que esteja no modo kernel, você provavelmente deveria usar as funções Nt *. Há um ramo extra que verifica se você está no modo kernel e, se não, executa toda a verificação de limites e verificação de parâmetros que o Nt * sempre faz. Assim, é muito menos eficiente chamá-los do modo de usuário.


As pessoas tentaram implementar o garfo no Windows. Esta é a coisa mais próxima que posso encontrar:

Retirado de: http://doxygen.scilab.org/5.3/d0/d8f/forkWindows_8c_source.html#l00216

static BOOL haveLoadedFunctionsForFork(void);

int fork(void) 
{
    HANDLE hProcess = 0, hThread = 0;
    OBJECT_ATTRIBUTES oa = { sizeof(oa) };
    MEMORY_BASIC_INFORMATION mbi;
    CLIENT_ID cid;
    USER_STACK stack;
    PNT_TIB tib;
    THREAD_BASIC_INFORMATION tbi;

    CONTEXT context = {
        CONTEXT_FULL | 
        CONTEXT_DEBUG_REGISTERS | 
        CONTEXT_FLOATING_POINT
    };

    if (setjmp(jenv) != 0) return 0; /* return as a child */

    /* check whether the entry points are 
       initilized and get them if necessary */
    if (!ZwCreateProcess && !haveLoadedFunctionsForFork()) return -1;

    /* create forked process */
    ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa,
        NtCurrentProcess(), TRUE, 0, 0, 0);

    /* set the Eip for the child process to our child function */
    ZwGetContextThread(NtCurrentThread(), &context);

    /* In x64 the Eip and Esp are not present, 
       their x64 counterparts are Rip and Rsp respectively. */
#if _WIN64
    context.Rip = (ULONG)child_entry;
#else
    context.Eip = (ULONG)child_entry;
#endif

#if _WIN64
    ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Rsp,
        MemoryBasicInformation, &mbi, sizeof mbi, 0);
#else
    ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Esp,
        MemoryBasicInformation, &mbi, sizeof mbi, 0);
#endif

    stack.FixedStackBase = 0;
    stack.FixedStackLimit = 0;
    stack.ExpandableStackBase = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
    stack.ExpandableStackLimit = mbi.BaseAddress;
    stack.ExpandableStackBottom = mbi.AllocationBase;

    /* create thread using the modified context and stack */
    ZwCreateThread(&hThread, THREAD_ALL_ACCESS, &oa, hProcess,
        &cid, &context, &stack, TRUE);

    /* copy exception table */
    ZwQueryInformationThread(NtCurrentThread(), ThreadBasicInformation,
        &tbi, sizeof tbi, 0);
    tib = (PNT_TIB)tbi.TebBaseAddress;
    ZwQueryInformationThread(hThread, ThreadBasicInformation,
        &tbi, sizeof tbi, 0);
    ZwWriteVirtualMemory(hProcess, tbi.TebBaseAddress, 
        &tib->ExceptionList, sizeof tib->ExceptionList, 0);

    /* start (resume really) the child */
    ZwResumeThread(hThread, 0);

    /* clean up */
    ZwClose(hThread);
    ZwClose(hProcess);

    /* exit with child's pid */
    return (int)cid.UniqueProcess;
}
static BOOL haveLoadedFunctionsForFork(void)
{
    HANDLE ntdll = GetModuleHandle("ntdll");
    if (ntdll == NULL) return FALSE;

    if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
        ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
        ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
    {
        return TRUE;
    }

    ZwCreateProcess = (ZwCreateProcess_t) GetProcAddress(ntdll,
        "ZwCreateProcess");
    ZwQuerySystemInformation = (ZwQuerySystemInformation_t)
        GetProcAddress(ntdll, "ZwQuerySystemInformation");
    ZwQueryVirtualMemory = (ZwQueryVirtualMemory_t)
        GetProcAddress(ntdll, "ZwQueryVirtualMemory");
    ZwCreateThread = (ZwCreateThread_t)
        GetProcAddress(ntdll, "ZwCreateThread");
    ZwGetContextThread = (ZwGetContextThread_t)
        GetProcAddress(ntdll, "ZwGetContextThread");
    ZwResumeThread = (ZwResumeThread_t)
        GetProcAddress(ntdll, "ZwResumeThread");
    ZwQueryInformationThread = (ZwQueryInformationThread_t)
        GetProcAddress(ntdll, "ZwQueryInformationThread");
    ZwWriteVirtualMemory = (ZwWriteVirtualMemory_t)
        GetProcAddress(ntdll, "ZwWriteVirtualMemory");
    ZwClose = (ZwClose_t) GetProcAddress(ntdll, "ZwClose");

    if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
        ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
        ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
    {
        return TRUE;
    }
    else
    {
        ZwCreateProcess = NULL;
        ZwQuerySystemInformation = NULL;
        ZwQueryVirtualMemory = NULL;
        ZwCreateThread = NULL;
        ZwGetContextThread = NULL;
        ZwResumeThread = NULL;
        ZwQueryInformationThread = NULL;
        ZwWriteVirtualMemory = NULL;
        ZwClose = NULL;
    }
    return FALSE;
}

Bem, o Windows realmente não tem nada parecido. Especialmente desde que fork pode ser usado para conceitualmente criar um thread ou um processo em * nix.

Então, eu tenho que dizer:

CreateProcess() / CreateProcessEx()

e

CreateThread() (Ouvi dizer que para aplicativos C, _beginthreadex() é melhor).


Não existe uma maneira fácil de emular o fork () no Windows.

Eu sugiro que você use tópicos em vez disso.


O documento a seguir fornece algumas informações sobre o código de portabilidade do UNIX para o Win32: https://msdn.microsoft.com/en-us/library/y23kc048.aspx

Entre outras coisas, indica que o modelo de processo é bastante diferente entre os dois sistemas e recomenda a consideração de CreateProcess e CreateThread, onde o comportamento fork () - like é necessário.







fork