ไลบรารี่พื้นฐานข้ามแพลตฟอร์ม https://github.com/hujianzhe/util ดาวน์โหลดและวางไว้ในไดเร็กทอรี BootServer
การแนะนำ:
โค้ดนี้ใช้เฉพาะการบูตโหนดบริการ การกำหนดเวลางาน และคำอธิบายโมดูลพื้นฐานเท่านั้น โดยจะไม่มีโค้ดธุรกิจใดๆ เลย โดยจะถูกนำไปใช้ใน Pure C โดยทั่วไปแล้วจะถูกคอมไพล์ลงในไลบรารีแบบไดนามิกและยังคงถูกจำกัดอย่างมากในแง่ของฟังก์ชันการใช้งาน ใช้โฟลว์โปรโตคอลทั่วไปบางส่วนและรองรับ C++ 20 Extension ของ stackless coroutine และแยกได้จากโค้ดบางโค้ดของไลบรารีไดนามิก C บริสุทธิ์ เพื่อป้องกันไม่ให้ C++ ปนเปื้อนเลเยอร์เฟรมเวิร์กและส่งผลกระทบต่อการสร้างไลบรารีไดนามิก
รหัสใน util รับผิดชอบข้ามแพลตฟอร์ม ยกเว้นว่าไม่จำเป็นต้องติดตั้งไลบรารีของบุคคลที่สาม
การแนะนำกระบวนการดำเนินงาน:
กระบวนการทางธุรกิจเรียกไลบรารีไดนามิกที่คอมไพล์โดยโค้ดและเรียกใช้อินเทอร์เฟซที่เกี่ยวข้องเพื่อใช้งาน สำหรับรายละเอียดเกี่ยวกับกระบวนการเรียก โปรดดูตัวอย่างโหนดทดสอบ (main_template ในไดเร็กทอรี BootServer คือชุดของเทมเพลตโค้ดเริ่มต้นตามกระบวนการ)
เธรดหลายตัวจัดการการอ่านและเขียน IO เครือข่ายภายในโมดูล เธรดการเข้าถึงที่ยอมรับแยกต่างหากจะเริ่มแรกเปิดเธรดผู้ปฏิบัติงานเพื่อประมวลผลข้อความภายในและรับข้อความเครือข่าย และส่งไปยังตรรกะรหัสธุรกิจของคุณ เธรดผู้ปฏิบัติงานใช้สแต็กคอร์รูทีนสำหรับการจัดกำหนดการการประมวลผล (ดูด้านล่างสำหรับเหตุผลว่าทำไมจึงไม่ใช้คอร์รูทีนแบบสแต็ก)
เธรดผู้ปฏิบัติงานใช้สแต็กคอร์รูทีนสำหรับการกำหนดเวลาตามค่าเริ่มต้นเพื่อรักษาความเข้ากันได้สูงสุด คุณยังสามารถใช้คอร์รูทีนแบบไม่มีสแต็กของ C ++ 20 (อันหนึ่งที่ใช้งานในไลบรารี util) สำหรับการกำหนดเวลาได้อย่างง่ายดาย มีคอร์รูทีนแบบสแต็กและกระบวนการแบบไร้สแต็กสามารถอยู่ร่วมกันได้
การแนะนำโมดูลและโค้ดตัวอย่าง:
1. BootServer: ส่วนของรหัสหลัก การเริ่มต้นที่จำเป็น และการทำงานของโหนดบริการ
2. ServiceTemplate: เทมเพลตรหัสโหนดบริการ ใช้เพื่อเขียนตรรกะทางธุรกิจของคุณ
3. SoTestClient, SoTestServer: ทดสอบโหนดและเขียนโค้ดตัวอย่างบางส่วน
4. Cpp20-SoTestServer: โหนดทดสอบ เขียนโค้ดตัวอย่างบางส่วน เปิดใช้งาน C++20 stackless coroutine ใน main.cpp (โดยใช้ C++20 stackless coroutine scheduler ในไลบรารี util)
รวบรวม:
คอมไพล์ VS โดยตรงของ Windows
ใช้ make debug / make release / make asan บน linux/Mac OS X
เริ่มต้น:
แก้ไขไฟล์การกำหนดค่าที่จำเป็นสำหรับการเริ่มต้นโหนดบริการ (ดูเทมเพลตไฟล์การกำหนดค่าที่แนบมาสำหรับรูปแบบเฉพาะ) และมอบไฟล์การกำหนดค่าและ ID ที่ไม่ซ้ำกัน ชื่อระบุบันทึก IP และหมายเลขพอร์ตให้แต่ละโหนด
Windows เปิดโดยตรงใน VS และโปรเจ็กต์ได้รับการกำหนดค่าด้วยพารามิเตอร์การเริ่มต้น <ไฟล์การกำหนดค่า>
หลังจากคอมไพล์ linux/mac แล้ว ให้ sh run.sh <กระบวนการบริการ> <ไฟล์การกำหนดค่า>
เหตุผลในการออกแบบและข้อมูลเชิงลึกบางประการ: ถาม: ทำไมไม่ใช้คอร์รูทีนแบบเรียงซ้อนแต่ใช้คอร์รูทีนแบบเรียงซ้อนล่ะ ตอบ: เป็นเรื่องง่ายที่จะใช้ coroutines แบบไม่มีสแต็กใน pure C (สำหรับโค้ดโดยละเอียด คุณสามารถดูตัวกำหนดเวลา coroutine แบบไม่มีสแต็กที่ใช้งานใน pure C ในไลบรารี util) แต่การรีไซเคิลทรัพยากรและการคงอยู่ (โดยเฉพาะตัวแปรในสแต็กนั้นขึ้นอยู่กับ coroutine ใหม่ -การเข้า) (สถานการณ์หลัง) เป็นเรื่องยากมาก หากคุณต้องการใช้ coroutine แบบไม่มีสแต็กอย่างราบรื่น คุณยังคงต้องอาศัยการสนับสนุนคอมไพเลอร์ ซึ่งสามารถทำได้ใน C++20 นอกจากนี้ยังมีการนำ C++20 stackless scheduler ไปใช้งานในไลบรารี util
ถาม: เหตุใด Coroutine แบบไม่มีสแต็กจึงมีฟังก์ชันเพิ่มเติมนี้ในรูปแบบของไฟล์ส่วนหัว
ตอบ: 1. เนื่องจาก coroutines แบบไม่มีสแต็กจะทำให้โค้ดรบกวน และจะเปลี่ยนรูปแบบลายเซ็นของฟังก์ชันจำนวนมาก
2. มีวัตถุ C++ ซึ่งไม่รู้จักในภาษา C และไม่สามารถส่งออกไลบรารีไดนามิกได้สำเร็จ
3. ให้ไว้ในรูปแบบของไฟล์ส่วนหัว การมอบสิทธิ์การเปิดใช้งานของ coroutines แบบสแต็กเลสให้กับเลเยอร์แอปพลิเคชันเป็นวิธีที่ฉันคิดอยู่ในปัจจุบันในการจัดการกับส่วนไลบรารีไดนามิก C บริสุทธิ์โดยไม่มีมลภาวะใดๆ
ถาม: สามารถแทนที่ด้วยตัวกำหนดเวลาอื่นได้หรือไม่
ตอบ: สามารถเปลี่ยนตัวกำหนดเวลาของเธรดของผู้ปฏิบัติงานได้ เธรดของผู้ปฏิบัติงานได้รับการออกแบบให้เป็นผู้ให้บริการที่รันอยู่ของตัวกำหนดตารางเวลา การโต้ตอบระหว่างเธรดเครือข่ายและเธรดของผู้ปฏิบัติงานภายในกรอบงานสามารถสอดคล้องกับพฤติกรรมการจัดกำหนดการผ่าน hook ของอินเทอร์เฟซ
ถาม: สามารถแทนที่ด้วยไลบรารีเครือข่ายอื่นได้หรือไม่
ตอบ: 1. ไม่สามารถแทนที่ด้วยไลบรารีเครือข่ายอื่นได้ในปัจจุบัน แต่ปัญหานี้ได้รับการพิจารณาตั้งแต่เริ่มต้นของการออกแบบ ส่วนเครือข่ายและส่วนการจัดกำหนดการงานจะถูกแยกออกจากกันโดยสิ้นเชิง ในอนาคต ลักษณะการทำงานที่สอดคล้องกันจะคล้ายกับเธรดของผู้ปฏิบัติงาน จะมีตะขอสำหรับเปลี่ยน
2. แม้ว่าจะมีไลบรารีเครือข่ายบุคคลที่สามจำนวนมาก แต่จุดสนใจของไลบรารีเหล่านั้นก็แตกต่างกัน มีไลบรารี TCP และ UDP ที่ใช้สำหรับการพัฒนาแอปพลิเคชัน นอกจากนี้ยังมีไลบรารีที่ต้องการรวมจักรวาลทั้งหมด และยังมีไลบรารีที่ใช้สแต็กโปรโตคอลเครือข่ายทั้งหมดที่เลเยอร์แอปพลิเคชัน ดังนั้นในความเป็นจริง พื้นที่นี้จึงไม่ได้รวมเป็นหนึ่งเดียว
3. หากชุดของไลบรารีเครือข่ายเข้าสู่มาตรฐานในอนาคต ฉันจะแทนที่ชุดนั้น
ถาม: ทำไมไม่ใช้ C++ เป็นเฟรมเวิร์กล่ะ
ตอบ: 1. เมื่อเขียนโค้ดชุดนี้ C++20 ยังไม่ปรากฏ ในขณะนั้น โซลูชัน Coroutine ที่ค่อนข้างสมบูรณ์ที่สุดคือ Stack Coroutine ซึ่งสามารถทำได้โดยใช้ C โดยการเรียก API ระบบแพลตฟอร์มที่เกี่ยวข้อง
2. ฟังก์ชั่นที่จะนำไปใช้โดยเฟรมเวิร์กประเภทนี้ได้รับการเสริมความแข็งแกร่งแล้ว และวงจรชีวิตของทรัพยากรก็แข็งแกร่งขึ้นโดยกระบวนการ เพียงเท่านี้ก็เพียงพอแล้วที่จะนำไปใช้ใน pure C (เคยมีเวอร์ชันที่ใช้งานใน C ++ มาก่อนและ รหัสมีความซับซ้อนมากขึ้น)
3. หากโมดูลอื่นเรียกไลบรารีแบบไดนามิก ยังคงจำเป็นต้องปิดผนึกอินเทอร์เฟซใน C
คลาสที่ส่งออก 4.C++ ติดต่อกันได้ และ ABI ไม่ได้รวมเป็นหนึ่งเดียว
ถาม: ชั้นธุรกิจสามารถพัฒนาต่อไปโดยใช้ pure C ได้หรือไม่
ตอบ: ไม่แนะนำอย่างยิ่ง เนื่องจากการเขียนกระบวนการอะซิงโครนัสและข้อยกเว้นในโมดูลที่เขียนด้วยภาษาระดับสูงทำให้กำหนดเวลาในการทำลายทรัพยากรไม่แน่นอน ในเวลานี้ การควบคุมทรัพยากรด้วยตนเองโดยใช้ C ล้วนๆ เป็นเรื่องยากมาก คุณควรใช้ภาษาระดับสูงกว่าเพื่อจัดการสิ่งเหล่านี้ ตัวอย่างเช่น คุณสามารถใช้ C++ เพื่อพัฒนารหัสธุรกิจระดับบนได้ และกลไก RAII ของมันสามารถรับประกันการเปิดตัวทรัพยากรที่เกี่ยวข้อง
ถาม: หากฉันต้องการแปลง "การโทรกลับ" ของโปรเจ็กต์เก่าให้เป็น "โครูทีน" ฉันสามารถแทนที่ส่วนตัวกำหนดตารางเวลาด้วยจุดโทรที่เกี่ยวข้องในรหัสธุรกิจได้หรือไม่
ตอบ: มันไม่ง่ายอย่างนั้น อย่างแรกคือปัญหาเวิร์กโหลด นอกจากนี้ ไม่ว่าจะเป็นในรูปแบบการโทรกลับหรือรูปแบบโครูทีน สิ่งสำคัญคือการออกคำขอและรอผลลัพธ์ในช่วงเวลานี้ซึ่งเป็นวงจรชีวิตของตัวแปร เป็นปัญหาที่ต้องแก้ไขและต้องพิจารณาให้รอบคอบ หากเป็น Raw pointer แทบจะเรียกได้ว่าแปลงไม่ได้หากใช้โปรเจ็กต์ไปแล้ว วิธีการต่างๆ เช่น std::shared_ptr จะทำให้วงจรชีวิตของตัวแปรยาวขึ้น ดังนั้นจึงยากน้อยลงในการแปลงเป็นเวอร์ชัน "stack coroutine" หากคุณต้องการแปลงเป็น C++20 stackless coroutine มีภาระงานมหาศาล เท่ากับการเขียนโปรเจ็กต์ใหม่ (เนื่องจาก coroutines ที่ไม่มีสแต็กมีการบุกรุกโค้ดที่รุนแรง) ดังนั้นจึงขอแนะนำว่าอย่าแปลงโปรเจ็กต์เก่า
ถาม: เหตุใด Coroutine จึงไม่ได้รับอนุญาตให้ย้ายไปยังเธรดอื่นเพื่อดำเนินการในปัจจุบัน
ตอบ: การย้ายโครูทีนสามารถทำได้ง่าย แต่สาเหตุที่ไม่ได้ระบุไว้คือ
1. งานที่ดำเนินการระหว่าง Coroutines นั้นไม่แน่นอน ซึ่งอาจทำให้ io และการคำนวณผสมกันในเธรดการกำหนดเวลาเดียวกัน
2. หลังจากการโยกย้าย กระบวนการ Coroutine เดียวกันอาจทำงานบนเธรดที่แตกต่างกัน ในกรณีนี้ คุณต้องแน่ใจว่าโค้ดของคุณไม่ได้ขึ้นอยู่กับตัวแปรภายในของเธรด แต่คุณไม่สามารถรับประกันได้ว่าไลบรารีของบริษัทอื่นไม่ได้ใช้ตัวแปรภายในของเธรด .
ถาม: อาซันจะพังเมื่อคอมไพล์และรันหรือไม่
ตอบ: 1. หากคุณใช้ Stacked Coroutine เริ่มต้นของเฟรมเวิร์ก ก็ไม่ใช่ปัญหาโค้ดแน่นอน คุณสามารถปรับขนาด Stacked Coroutine ในไฟล์การกำหนดค่าโหนดได้ (เมื่อเปิดใช้งาน ASAN พื้นที่สแต็กที่ค่อนข้างใหญ่จะถูกใช้ จึงมีความเป็นไปได้ที่จะเกิดการระเบิดของกองซ้อน)
2. ASAN ไม่รองรับ stacked coroutine API (ucontext) อย่างสมบูรณ์ในสภาพแวดล้อม Unix แม้ว่า ucontext coroutine API จะถูกปรับให้เข้ากับ ASAN ในโค้ด util แล้ว แต่ก็ยังไม่สามารถรับประกันได้ 100% ว่าจะไม่มีปัญหาในการทำงานใน ASAN สภาพแวดล้อม (จนถึงตอนนี้ดีมาก)
3. ใน Linux รุ่นใหม่บางรุ่น หาก ASAN ส่งออก AddressSanitizer: DEADLYSIGNAL ไม่จำกัด ให้ปรับ sudo sysctl vm.mmap_rnd_bits=28 เพื่อแก้ไขปัญหา
สิ่งที่ต้องทำ:
1. ฉันไม่มีเวลาเขียนเอกสารโดยละเอียดจริงๆ
2. ให้การสนับสนุนสำหรับการเขียนตรรกะทางธุรกิจในภาษาสคริปต์