Думаю, в этом вопросе все сказано.
Хочу форк на Windows. Какая операция наиболее похожа и как ее использовать.
Cygwin имеет полнофункциональную fork () в Windows. Таким образом, если использование Cygwin для вас приемлемо, тогда проблема решается, если производительность не является проблемой.
В противном случае вы можете посмотреть, как Cygwin реализует fork (). Из довольно старого архитектурного документа Cygwin :
5.6. Создание процесса. Вызов fork в Cygwin особенно интересен, потому что он плохо отображается поверх Win32 API. Это очень затрудняет правильную реализацию. В настоящее время вилка Cygwin - это реализация без копирования при записи, аналогичная той, что присутствовала в ранних версиях UNIX.
Первое, что происходит, когда родительский процесс разветвляет дочерний процесс, - это то, что родитель инициализирует пространство в таблице процессов Cygwin для дочернего процесса. Затем он создает приостановленный дочерний процесс с помощью вызова Win32 CreateProcess. Затем родительский процесс вызывает setjmp для сохранения своего собственного контекста и устанавливает указатель на него в общей области памяти Cygwin (совместно используемой всеми задачами Cygwin). Затем он заполняет дочерние разделы .data и .bss, копируя из своего собственного адресного пространства в приостановленное дочернее адресное пространство. После инициализации адресного пространства дочернего элемента дочерний элемент запускается, пока родитель ждет мьютекса. Ребенок обнаруживает, что он был разветвлен, и прыгает в длину, используя сохраненный буфер перехода. Затем дочерний элемент устанавливает мьютекс, которого ожидает родитель, и блокирует другой мьютекс. Это сигнал для родителя скопировать свой стек и кучу в дочерний, после чего он освобождает мьютекс, которого ожидает дочерний элемент, и возвращается из вызова fork. Наконец, дочерний элемент просыпается от блокировки на последнем мьютексе, воссоздает все отображенные в память области, переданные ему через общую область, и возвращается из самого fork.
Хотя у нас есть некоторые идеи относительно того, как ускорить реализацию нашей вилки за счет уменьшения количества переключений контекста между родительским и дочерним процессом, вилка почти всегда будет неэффективной в Win32. К счастью, в большинстве случаев семейство вызовов spawn, предоставляемое Cygwin, может быть заменено парой fork / exec с небольшим усилием. Эти вызовы четко отображаются поверх Win32 API. В результате они намного эффективнее. Изменение программы драйвера компилятора для вызова spawn вместо fork было тривиальным изменением и увеличило скорость компиляции на двадцать-тридцать процентов в наших тестах.
Однако spawn и exec представляют свой набор трудностей. Поскольку в Win32 невозможно выполнить реальный запуск, Cygwin должен изобретать свои собственные идентификаторы процессов (PID). В результате, когда процесс выполняет несколько вызовов exec, будет несколько идентификаторов Windows PID, связанных с одним Cygwin PID. В некоторых случаях заглушки каждого из этих процессов Win32 могут задерживаться, ожидая завершения их процесса exec'd Cygwin.
Похоже, много работы, не так ли? И да, это медленно.
РЕДАКТИРОВАТЬ: документ устарел, см. Этот отличный ответ для обновления
fork
но достигает этого с помощью ненадежного решения, и вы должны быть готовы к неожиданным ситуациям.Я, конечно, не знаю подробностей об этом, потому что я никогда этого не делал, но собственный NT API имеет возможность разветвлять процесс (подсистема POSIX в Windows нуждается в этой возможности - я не уверен, что подсистема POSIX даже не поддерживается).
Поиск по ZwCreateProcess () должен дать вам более подробную информацию - например, эту информацию от Максима Шацких :
Однако обратите внимание, что Коринна Виншен указывает, что Cygwin, обнаруженный с помощью ZwCreateProcess (), все еще ненадежен :
источник
fork
с немедленнымexec
», то, возможно, подойдет CreateProcess. Ноfork
без этогоexec
часто желательно, и именно это заставляет людей просить настоящихfork
.Что ж, в windows действительно нет ничего похожего. Тем более, что fork можно использовать для концептуального создания потока или процесса в * nix.
Итак, я должен сказать:
CreateProcess()
/CreateProcessEx()
и
CreateThread()
(Я слышал, что для приложений C_beginthreadex()
лучше).источник
Люди пытались реализовать форк в Windows. Это самое близкое к нему, что я могу найти:
Взято с: http://doxygen.scilab.org/5.3/d0/d8f/forkWindows_8c_source.html#l00216
источник
fork
сбой, произойдет сбой программы или просто произойдет сбой потока? Если это приводит к сбою программы, то на самом деле это не разветвление. Просто любопытно, потому что я ищу реальное решение и надеюсь, что это может быть достойной альтернативой.До того, как Microsoft представила свою новую опцию «Подсистема Linux для Windows», это
CreateProcess()
было ближе всего к Windows.fork()
, но Windows требует, чтобы вы указали исполняемый файл для запуска в этом процессе.Процесс создания UNIX сильно отличается от Windows. Его
fork()
вызов практически полностью дублирует текущий процесс, каждый в своем адресном пространстве, и продолжает их запускать отдельно. Хотя сами процессы разные, они по-прежнему выполняют одну и ту же программу. См. Здесь хороший обзорfork/exec
модели.Возвращаясь назад, эквивалент Windows
CreateProcess()
- этоfork()/exec()
пара функций в UNIX.Если вы переносили программное обеспечение на Windows и не возражаете против уровня перевода, Cygwin предоставил вам нужные возможности, но это было довольно беспорядочно.
Конечно, с новой подсистемой Linux самое близкое к Windows
fork()
- этоfork()
:-)источник
fork
в обычном приложении, отличном от WSL?В следующем документе представлена некоторая информация о переносе кода с UNIX на Win32: https://msdn.microsoft.com/en-us/library/y23kc048.aspx
Среди прочего, он указывает на то, что модель процесса в двух системах сильно различается, и рекомендует рассмотреть CreateProcess и CreateThread, где требуется поведение, подобное fork ().
источник
"как только вы захотите получить доступ к файлу или printf, тогда io будет отказано"
Вы не можете съесть свой торт и съесть его ... в msvcrt.dll printf () основан на API консоли, который сам по себе использует lpc для связи с подсистемой консоли (csrss.exe). Соединение с csrss инициируется при запуске процесса, что означает, что любой процесс, который начинает свое выполнение «посередине», будет пропускать этот шаг. Если у вас нет доступа к исходному коду операционной системы, нет смысла пытаться подключиться к csrss вручную. Вместо этого вы должны создать свою собственную подсистему и, соответственно, избегать функций консоли в приложениях, использующих fork ().
как только вы реализовали свою собственную подсистему, не забудьте также продублировать все родительские дескрипторы для дочернего процесса ;-)
«Кроме того, вам, вероятно, не следует использовать функции Zw *, если вы не находитесь в режиме ядра, вместо этого вам, вероятно, следует использовать функции Nt *».
ZwGetContextThread (NtCurrentThread (), & контекст);
источник
Семантика fork () необходима там, где дочернему элементу требуется доступ к фактическому состоянию памяти родительского объекта на момент вызова fork (). У меня есть программа, которая полагается на неявный мьютекс копирования памяти при вызове функции fork (), что делает невозможным использование потоков. (Это эмулируется на современных платформах * nix с помощью семантики таблицы копирования при записи / обновления в памяти.)
Ближайшим из существующих в Windows системных вызовов является CreateProcess. Лучшее, что можно сделать, - это чтобы родительский объект заморозил все другие потоки на время, когда он копирует память в пространство памяти нового процесса, а затем разморозил их. Я вижу, что ни класс Cygwin frok, ни код Scilab, опубликованный Эриком де Курти, не останавливают потоки.
Кроме того, вам, вероятно, не следует использовать функции Zw *, если вы не находитесь в режиме ядра, вместо этого вам, вероятно, следует использовать функции Nt *. Есть дополнительная ветка, которая проверяет, находитесь ли вы в режиме ядра, и, если нет, выполняет все проверки границ и параметров, которые всегда выполняет Nt *. Таким образом, вызывать их из пользовательского режима немного менее эффективно.
источник
Лучшие варианты - CreateProcess () или CreateThread () . Существует более подробная информация о переносе здесь .
источник
Нет простого способа эмулировать fork () в Windows.
Я предлагаю вам вместо этого использовать потоки.
источник
fork
была именно тем , что сделала CygWin. Но, если вы когда-нибудь читали о том, как они это сделали, ваш «нелегкий путь» будет большим недоразумением :-)Самое близкое, что вы скажете ... Дайте подумать ... Наверное, это fork () :)
Подробнее см. Реализует ли Interix fork ()?
источник
Как уже упоминалось в других ответах, NT (ядро, лежащее в основе современных версий Windows) имеет эквивалент Unix fork (). Проблема не в этом.
Проблема в том, что клонирование всего состояния процесса, как правило, неразумно. Это так же верно в мире Unix, как и в Windows, но в мире Unix fork () используется постоянно, и библиотеки предназначены для работы с этим. Библиотеки Windows - нет.
Например, системные библиотеки DLL kernel32.dll и user32.dll поддерживают частное соединение с серверным процессом Win32 csrss.exe. После вилки на клиентской стороне этого соединения есть два процесса, которые могут вызвать проблемы. Дочерний процесс должен сообщить csrss.exe о своем существовании и установить новое соединение, но для этого нет интерфейса, поскольку эти библиотеки не были разработаны с учетом fork ().
Итак, у вас есть два варианта. Один из них - запретить использование kernel32 и user32 и других библиотек, которые не предназначены для разветвления, включая любые библиотеки, которые прямо или косвенно ссылаются на kernel32 или user32, то есть практически все из них. Это означает, что вы вообще не можете взаимодействовать с рабочим столом Windows и застряли в своем собственном отдельном мире Unixy. Это подход, используемый различными подсистемами Unix для NT.
Другой вариант - прибегнуть к какой-то ужасной хитрости, чтобы попытаться заставить неосведомленные библиотеки работать с fork (). Это то, что делает Cygwin. Он создает новый процесс, позволяет ему инициализироваться (включая регистрацию с помощью csrss.exe), затем копирует большую часть динамического состояния из старого процесса и надеется на лучшее. Меня поражает, что это когда-либо работает. Он определенно не работает надежно - даже если он не выходит из строя случайным образом из-за конфликта адресного пространства, любая используемая вами библиотека может оставаться в неработающем состоянии. Утверждение текущего принятого ответа о том, что Cygwin имеет «полнофункциональную вилку ()» ... сомнительно.
Резюме: В среде, подобной Interix, вы можете выполнить вилку, вызвав fork (). В противном случае попробуйте отучить себя от этого желания. Даже если вы нацелены на Cygwin, не используйте fork (), если в этом нет крайней необходимости.
источник
Если вас интересует только создание подпроцесса и его ожидание, возможно, достаточно _spawn * API в process.h. Подробнее об этом:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/process-and-environment-control https://en.wikipedia.org/wiki/Process.h
источник