ฉันเดาว่าคำถามพูดได้ทั้งหมด
ฉันต้องการแยกบน Windows การทำงานที่คล้ายกันมากที่สุดคืออะไรและฉันจะใช้มันอย่างไร
ฉันเดาว่าคำถามพูดได้ทั้งหมด
ฉันต้องการแยกบน Windows การทำงานที่คล้ายกันมากที่สุดคืออะไรและฉันจะใช้มันอย่างไร
คำตอบ:
Cygwinมี fork () ที่โดดเด่นบน Windows ดังนั้นหากคุณยอมรับการใช้ Cygwin ปัญหาจะได้รับการแก้ไขในประสิทธิภาพของเคสไม่ใช่ปัญหา
มิฉะนั้นคุณสามารถดูวิธีที่ Cygwin ใช้ fork () จากเอกสารสถาปัตยกรรมของ Cygwin ที่ค่อนข้างเก่า:
5.6 การสร้างกระบวนการการเรียก Fork ใน Cygwin นั้นน่าสนใจเป็นอย่างยิ่งเพราะมันไม่ได้แมปที่ด้านบนของ Win32 API ทำให้ยากมากที่จะนำไปใช้อย่างถูกต้อง ปัจจุบันส้อม Cygwin เป็นการนำไปใช้งานแบบไม่คัดลอกเมื่อเขียนคล้ายกับสิ่งที่มีอยู่ใน UNIX ในช่วงแรก ๆ
สิ่งแรกที่เกิดขึ้นเมื่อกระบวนการหลักแยกกระบวนการลูกคือพาเรนต์เริ่มต้นช่องว่างในตารางกระบวนการ Cygwin สำหรับเด็ก จากนั้นจะสร้างกระบวนการลูกที่ถูกระงับโดยใช้การเรียก Win32 CreateProcess จากนั้นกระบวนการหลักจะเรียกใช้ setjmp เพื่อบันทึกบริบทของตนเองและตั้งค่าตัวชี้ไปที่สิ่งนี้ในพื้นที่หน่วยความจำแบบแบ่งใช้ของ Cygwin (แบ่งใช้ระหว่างงาน Cygwin ทั้งหมด) จากนั้นกรอกข้อมูลในส่วน. data และ. bss ของเด็กโดยคัดลอกจากช่องที่อยู่ของตัวเองลงในช่องที่อยู่ของเด็กที่ถูกระงับ หลังจากเริ่มต้นพื้นที่แอดเดรสของเด็กแล้วเด็กจะถูกเรียกใช้ในขณะที่ผู้ปกครองรอใน mutex เด็กพบว่ามันถูกส้อมและกระโดดไกลโดยใช้บัฟเฟอร์กระโดดที่บันทึกไว้ จากนั้นเด็กจะตั้งค่า mutex ที่พาเรนต์รออยู่และบล็อกบน mutex อื่น นี่คือสัญญาณสำหรับผู้ปกครองในการคัดลอกสแต็กและฮีพลงในลูกหลังจากนั้นจะปล่อย mutex ที่เด็กรออยู่และกลับมาจากการเรียกส้อม ในที่สุดเด็กก็ตื่นจากการบล็อกบน mutex สุดท้ายสร้างพื้นที่ที่แมปหน่วยความจำส่งผ่านไปยังพื้นที่ที่ใช้ร่วมกันอีกครั้งและกลับมาจากทางแยก
ในขณะที่เรามีแนวคิดบางอย่างเกี่ยวกับวิธีเพิ่มความเร็วในการใช้งาน fork ของเราโดยการลดจำนวนการสลับบริบทระหว่างกระบวนการพาเรนต์และโปรเซสลูกส้อมมักจะไม่มีประสิทธิภาพภายใต้ Win32 โชคดีที่ในสถานการณ์ส่วนใหญ่ตระกูลการโทรของ Cygwin สามารถใช้แทนคู่ส้อม / Exec ได้ด้วยความพยายามเพียงเล็กน้อย การเรียกเหล่านี้จะแมปที่ด้านบนของ Win32 API เป็นผลให้มีประสิทธิภาพมากขึ้น การเปลี่ยนโปรแกรมไดรเวอร์ของคอมไพเลอร์เพื่อเรียก spawn แทน fork เป็นการเปลี่ยนแปลงเล็กน้อยและเพิ่มความเร็วในการรวบรวมขึ้นยี่สิบถึงสามสิบเปอร์เซ็นต์ในการทดสอบของเรา
อย่างไรก็ตามการวางไข่และผู้บริหารนำเสนอชุดความยากลำบากของตนเอง เนื่องจากไม่มีวิธีดำเนินการ exec จริงภายใต้ Win32 Cygwin จึงต้องคิดค้น Process IDs (PIDs) ของตัวเอง ด้วยเหตุนี้เมื่อกระบวนการดำเนินการเรียกผู้บริหารหลายคนจะมี Windows PID หลายตัวที่เชื่อมโยงกับ Cygwin PID เดียว ในบางกรณีต้นขั้วของแต่ละกระบวนการ Win32 เหล่านี้อาจค้างอยู่รอให้กระบวนการ Cygwin ของผู้บริหารออกจากระบบ
ฟังดูเหมือนงานเยอะใช่ไหม และใช่มันเป็น slooooow
แก้ไข: เอกสารล้าสมัยโปรดดูคำตอบที่ยอดเยี่ยมสำหรับการอัปเดต
fork
แต่มันก็ทำได้ด้วยวิธีแก้ปัญหารั่วและคุณต้องเตรียมพร้อมสำหรับสถานการณ์ที่ไม่คาดคิด
ฉันไม่รู้รายละเอียดเกี่ยวกับเรื่องนี้อย่างแน่นอนเพราะฉันไม่เคยทำมาก่อน แต่ NT API ดั้งเดิมมีความสามารถในการแยกกระบวนการ (ระบบย่อย POSIX บน Windows ต้องการความสามารถนี้ - ฉันไม่แน่ใจว่าระบบย่อย POSIX ได้รับการสนับสนุนอีกต่อไป)
การค้นหา ZwCreateProcess () ควรให้รายละเอียดเพิ่มเติมแก่คุณตัวอย่างเช่นข้อมูลเล็กน้อยจาก Maxim Shatskih :
พารามิเตอร์ที่สำคัญที่สุดคือ SectionHandle หากพารามิเตอร์นี้เป็น NULL เคอร์เนลจะแยกกระบวนการปัจจุบัน มิฉะนั้นพารามิเตอร์นี้จะต้องเป็นหมายเลขอ้างอิงของวัตถุส่วน SEC_IMAGE ที่สร้างบนไฟล์ EXE ก่อนที่จะเรียก ZwCreateProcess ()
แม้ว่าจะทราบว่าCorinna Vinschen ระบุว่า Cygwin พบโดยใช้ ZwCreateProcess () ยังไม่น่าเชื่อถือ :
Iker Arizmendi เขียนว่า:
> Because the Cygwin project relied solely on Win32 APIs its fork > implementation is non-COW and inefficient in those cases where a fork > is not followed by exec. It's also rather complex. See here (section > 5.6) for details: > > http://www.redhat.com/support/wpapers/cygnus/cygnus_cygwin/architecture.html
เอกสารนี้ค่อนข้างเก่า 10 ปีหรือมากกว่านั้น ในขณะที่เรายังคงใช้การเรียก Win32 เพื่อเลียนแบบ fork วิธีการเปลี่ยนไปอย่างเห็นได้ชัด โดยเฉพาะอย่างยิ่งเราจะไม่สร้างกระบวนการย่อยในสถานะที่ถูกระงับอีกต่อไปเว้นแต่ว่าข้อมูลเฉพาะจะต้องมีการจัดการพิเศษในพาเรนต์ก่อนที่จะคัดลอกไปยังลูก ใน 1.5.25 รีลีสปัจจุบันกรณีเดียวสำหรับเด็กที่ถูกระงับคือซ็อกเก็ตแบบเปิดในพาเรนต์ 1.7.0 ที่กำลังจะมาถึงจะไม่ถูกระงับเลย
เหตุผลหนึ่งที่จะไม่ใช้ ZwCreateProcess คือถึงรุ่น 1.5.25 เรายังคงรองรับผู้ใช้ Windows 9x อย่างไรก็ตามความพยายามสองครั้งในการใช้ ZwCreateProcess บนระบบที่ใช้ NT ล้มเหลวด้วยเหตุผลใดเหตุผลหนึ่ง
มันจะดีมากถ้าสิ่งนี้จะดีกว่าหรือได้รับการจัดทำเป็นเอกสารโดยเฉพาะโครงสร้างข้อมูลสองสามอย่างและวิธีเชื่อมต่อกระบวนการกับระบบย่อย แม้ว่า fork ไม่ใช่แนวคิดของ Win32 แต่ฉันก็ไม่เห็นว่ามันจะเป็นเรื่องเลวร้ายที่จะทำให้ fork ง่ายขึ้น
fork
ทันทีexec
" บางที CreateProcess อาจเป็นผู้สมัคร แต่fork
โดยไม่ต้องมักจะเป็นที่พึงประสงค์และนี่คือสิ่งที่คนขับรถคนที่จะขอให้จริงexec
fork
หน้าต่างไม่ค่อยมีอะไรเหมือนกัน โดยเฉพาะอย่างยิ่งเนื่องจากสามารถใช้ fork เพื่อสร้างเธรดหรือกระบวนการในแนวความคิดใน * nix
ดังนั้นฉันต้องพูดว่า:
CreateProcess()
/CreateProcessEx()
และ
CreateThread()
(ฉันเคยได้ยินมาว่าสำหรับแอปพลิเคชัน C _beginthreadex()
จะดีกว่า)
มีคนพยายามใช้ fork บน Windows นี่คือสิ่งที่ใกล้เคียงที่สุดที่ฉันสามารถหาได้:
นำมาจาก: 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;
}
fork
เกิดข้อขัดข้องโปรแกรมขัดข้องหรือเธรดล่มหรือไม่ หากโปรแกรมขัดข้องแสดงว่านี่ไม่ใช่การฟอร์คจริงๆ แค่อยากรู้เพราะฉันกำลังมองหาวิธีแก้ปัญหาที่แท้จริงและหวังว่านี่อาจเป็นทางเลือกที่ดี
ก่อนที่ Microsoft จะแนะนำตัวเลือก "ระบบย่อย Linux สำหรับ Windows" ใหม่CreateProcess()
เป็นสิ่งที่ใกล้เคียงที่สุดที่ Windows ต้องทำfork()
แต่ Windows ต้องการให้คุณระบุไฟล์ปฏิบัติการเพื่อเรียกใช้ในกระบวนการนั้น
การสร้างกระบวนการ UNIX แตกต่างจาก Windows ค่อนข้างมาก fork()
โดยพื้นฐานแล้วการเรียกของมันจะทำซ้ำกระบวนการปัจจุบันเกือบทั้งหมดโดยแต่ละอย่างจะอยู่ในพื้นที่ที่อยู่ของตัวเองและยังคงเรียกใช้งานแยกกัน แม้ว่ากระบวนการจะแตกต่างกัน แต่ก็ยังรันโปรแกรมเดียวกัน ดูที่นี่สำหรับภาพรวมที่ดีของfork/exec
รุ่น
ย้อนกลับไปทางอื่นสิ่งที่เทียบเท่ากับ Windows CreateProcess()
คือfork()/exec()
คู่ของฟังก์ชันใน UNIX
หากคุณกำลังพอร์ตซอฟต์แวร์ไปที่ Windows และคุณไม่สนใจเลเยอร์การแปล Cygwin ก็ให้ความสามารถตามที่คุณต้องการ แต่มันค่อนข้างไม่ดี
แน่นอนกับใหม่ระบบย่อยลินุกซ์ , สิ่งที่ใกล้เคียง Windows มีจะfork()
เป็นจริง fork()
:-)
fork
ในแอปพลิเคชันที่ไม่ใช่ WSL โดยเฉลี่ยได้หรือไม่?
เอกสารต่อไปนี้ให้ข้อมูลบางส่วนเกี่ยวกับการย้ายรหัสจาก UNIX ไปยัง Win32: https://msdn.microsoft.com/en-us/library/y23kc048.aspx
เหนือสิ่งอื่นใดมันบ่งชี้ว่ารูปแบบกระบวนการค่อนข้างแตกต่างกันระหว่างทั้งสองระบบและแนะนำให้พิจารณา CreateProcess และ CreateThread ซึ่งจำเป็นต้องมีลักษณะการทำงานเหมือน fork ()
"ทันทีที่คุณต้องการเข้าถึงไฟล์หรือ printf io จะถูกปฏิเสธ"
คุณไม่สามารถมีเค้กของคุณและกินมันได้เช่นกัน ... ใน msvcrt.dll printf () ขึ้นอยู่กับ Console API ซึ่งในตัวเองใช้ lpc เพื่อสื่อสารกับระบบย่อยของคอนโซล (csrss.exe) การเชื่อมต่อกับ csrss เริ่มต้นเมื่อเริ่มต้นกระบวนการซึ่งหมายความว่ากระบวนการใด ๆ ที่เริ่มต้นการดำเนินการ "ตรงกลาง" จะมีการข้ามขั้นตอนนั้น หากคุณไม่สามารถเข้าถึงซอร์สโค้ดของระบบปฏิบัติการได้คุณจะพยายามเชื่อมต่อกับ csrss ด้วยตนเองไม่ได้ คุณควรสร้างระบบย่อยของคุณเองแทนและหลีกเลี่ยงฟังก์ชันคอนโซลในแอปพลิเคชันที่ใช้ fork ()
เมื่อคุณติดตั้งระบบย่อยของคุณเองแล้วอย่าลืมทำซ้ำแฮนเดิลทั้งหมดของผู้ปกครองสำหรับกระบวนการย่อย ;-)
"นอกจากนี้คุณอาจไม่ควรใช้ฟังก์ชัน Zw * เว้นแต่คุณจะอยู่ในโหมดเคอร์เนลคุณควรใช้ฟังก์ชัน Nt * แทน"
ZwGetContextThread (NtCurrentThread () & บริบท);
ไม่มีวิธีง่ายๆในการเลียนแบบ fork () บน Windows
ฉันขอแนะนำให้คุณใช้เธรดแทน
fork
เป็นว่าสิ่งที่ Cygwin ได้ แต่ถ้าคุณเคยอ่านเกี่ยวกับวิธีการที่พวกเขาทำหรือ "ไม่ง่ายเลย" ถือเป็นการแสดงความเข้าใจผิดอย่างร้ายแรง :-)
จำเป็นต้องมีความหมาย fork () ที่เด็กต้องการเข้าถึงสถานะหน่วยความจำจริงของพาเรนต์เมื่อมีการเรียกใช้ส้อม () ทันที ฉันมีซอฟต์แวร์ชิ้นหนึ่งซึ่งอาศัย mutex โดยนัยของการคัดลอกหน่วยความจำตามที่เรียกว่า instant fork () ซึ่งทำให้เธรดไม่สามารถใช้งานได้ (สิ่งนี้ถูกจำลองบนแพลตฟอร์ม * nix ที่ทันสมัยผ่านความหมายของตารางคัดลอกเมื่อเขียน / อัปเดตหน่วยความจำ)
สิ่งที่ใกล้เคียงที่สุดที่มีอยู่ใน Windows ในฐานะ syscall คือ CreateProcess วิธีที่ดีที่สุดที่สามารถทำได้คือให้พาเรนต์ตรึงเธรดอื่น ๆ ทั้งหมดในช่วงเวลาที่กำลังคัดลอกหน่วยความจำไปยังพื้นที่หน่วยความจำของกระบวนการใหม่จากนั้นจึงละลาย ทั้งคลาส Cygwin frok [sic] และรหัส Scilab ที่ Eric des Courtis โพสต์ไม่ได้ทำให้เธรดหยุดนิ่งอย่างที่ฉันเห็น
นอกจากนี้คุณอาจไม่ควรใช้ฟังก์ชัน Zw * เว้นแต่คุณจะอยู่ในโหมดเคอร์เนลคุณควรใช้ฟังก์ชัน Nt * แทน มีสาขาพิเศษที่ตรวจสอบว่าคุณอยู่ในโหมดเคอร์เนลหรือไม่และหากไม่ดำเนินการตรวจสอบขอบเขตทั้งหมดและการตรวจสอบพารามิเตอร์ที่ Nt * ทำอยู่เสมอ ดังนั้นจึงมีประสิทธิภาพน้อยกว่าเล็กน้อยในการเรียกใช้จากโหมดผู้ใช้
ดังที่คำตอบอื่น ๆ ได้กล่าวไว้ NT (เคอร์เนลที่อยู่ภายใต้ Windows รุ่นใหม่ล่าสุด) มีคุณสมบัติเทียบเท่า Unix fork () นั่นไม่ใช่ปัญหา
ปัญหาคือการโคลนสถานะทั้งหมดของกระบวนการโดยทั่วไปไม่ใช่เรื่องที่ควรทำ นี่เป็นเรื่องจริงในโลก Unix เช่นเดียวกับใน Windows แต่ในโลก Unix จะใช้ fork () ตลอดเวลาและไลบรารีได้รับการออกแบบมาเพื่อจัดการกับมัน ไลบรารี Windows ไม่ได้
ตัวอย่างเช่นระบบ DLLs kernel32.dll และ user32.dll รักษาการเชื่อมต่อส่วนตัวกับกระบวนการเซิร์ฟเวอร์ Win32 csrss.exe หลังจากส้อมมีสองกระบวนการที่ไคลเอนต์สิ้นสุดของการเชื่อมต่อนั้นซึ่งจะทำให้เกิดปัญหา กระบวนการลูกควรแจ้ง csrss.exe ถึงการมีอยู่ของมันและทำการเชื่อมต่อใหม่ - แต่ไม่มีอินเทอร์เฟซสำหรับทำเช่นนั้นเนื่องจากไลบรารีเหล่านี้ไม่ได้ออกแบบมาโดยคำนึงถึง fork ()
คุณจึงมีสองทางเลือก ประการแรกคือห้ามใช้ kernel32 และ user32 และไลบรารีอื่น ๆ ที่ไม่ได้ออกแบบมาเพื่อแยกรวมถึงไลบรารีใด ๆ ที่เชื่อมโยงโดยตรงหรือโดยอ้อมไปยัง kernel32 หรือ user32 ซึ่งแทบทั้งหมด ซึ่งหมายความว่าคุณไม่สามารถโต้ตอบกับเดสก์ท็อป Windows ได้เลยและติดอยู่ในโลก Unixy ที่แยกจากกันของคุณเอง นี่คือแนวทางที่ดำเนินการโดยระบบย่อย Unix สำหรับ NT ต่างๆ
อีกทางเลือกหนึ่งคือหันไปใช้การแฮ็กที่น่ากลัวบางอย่างเพื่อพยายามทำให้ไลบรารีที่ไม่รู้จักทำงานร่วมกับ fork () นั่นคือสิ่งที่ Cygwin ทำ สร้างกระบวนการใหม่ให้เริ่มต้น (รวมถึงการลงทะเบียนตัวเองด้วย csrss.exe) จากนั้นคัดลอกสถานะไดนามิกส่วนใหญ่จากกระบวนการเก่าและหวังว่าจะได้สิ่งที่ดีที่สุด มัน amazes ฉันว่านี้เคยทำงาน แน่นอนว่ามันใช้งานไม่ได้อย่างน่าเชื่อถือแม้ว่ามันจะไม่ล้มเหลวแบบสุ่มเนื่องจากความขัดแย้งของพื้นที่แอดเดรสไลบรารีใด ๆ ที่คุณใช้อยู่อาจถูกทิ้งไว้ในสถานะเสีย คำกล่าวอ้างของคำตอบที่ได้รับการยอมรับในปัจจุบันว่า Cygwin มี "fully-features fork ()" นั้น ... น่าสงสัย
สรุป: ในสภาพแวดล้อมแบบ Interix คุณสามารถแยกโดยการเรียก fork () มิฉะนั้นโปรดพยายามหย่านมตัวเองจากความปรารถนาที่จะทำ แม้ว่าคุณจะกำหนดเป้าหมายไปที่ Cygwin อย่าใช้ fork () เว้นแต่คุณจะต้องทำอย่างแน่นอน
ตัวเลือกที่ดีที่สุดของคุณจะCreateProcess ()หรือCreateThread () มีข้อมูลเพิ่มเติมเกี่ยวกับการย้ายที่นี่
ใกล้เคียงที่สุดที่คุณพูด ... ขอฉันคิดว่า ... นี่ต้องเป็นส้อม () ฉันเดา :)
ดูรายละเอียดได้ที่Interix ใช้ fork () หรือไม่
หากคุณสนใจแค่การสร้างกระบวนการย่อยและรอมันบางที _spawn * API อยู่ระหว่างดำเนินการ h ก็เพียงพอแล้ว นี่คือข้อมูลเพิ่มเติมเกี่ยวกับสิ่งนั้น:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/process-and-environment-control https://en.wikipedia.org/wiki/Process.h