การล็อกทรัพยากรด้วย async/await

ฉันมีแอปพลิเคชันที่ฉันมีทรัพยากรที่ใช้ร่วมกัน (ระบบ Motion) ซึ่งลูกค้าหลายรายสามารถเข้าถึงได้ ฉันมีการดำเนินการส่วนบุคคลที่ต้องการการเข้าถึงระบบในช่วงระยะเวลาของการย้าย และการดำเนินการใดควรทำให้เกิดข้อยกเว้น 'ไม่ว่าง' หากมีการร้องขอการดำเนินการที่ขัดแย้งกันในเวลาเดียวกัน ฉันยังมีซีเควนเซอร์ซึ่งจำเป็นต้องได้รับสิทธิ์การเข้าถึงระบบ Motion แบบเอกสิทธิ์เฉพาะบุคคลเพื่อดำเนินการต่างๆ สลับกับการกระทำอื่นๆ ในระหว่างลำดับทั้งหมด ไคลเอ็นต์อื่นไม่ควรสามารถรัน Operations ได้

ฉันได้เข้าหาสิ่งนี้แบบดั้งเดิมโดยใช้ความสัมพันธ์ของเธรด เพื่อให้เธรดสามารถร้องขอการเข้าถึงแบบเอกสิทธิ์เฉพาะบุคคลและเรียกใช้การบล็อกการโทรที่สอดคล้องกับการดำเนินการ ในขณะที่เธรดมีสิทธิ์เข้าถึง ไม่มีเธรดอื่นใดที่สามารถใช้ทรัพยากรได้ ปัญหาที่ฉันมีตอนนี้คือฉันได้ก้าวไปสู่การนำระบบของฉันไปใช้โดยใช้รูปแบบ async/await เพื่อให้มีการใช้ซีเควนเซอร์ที่สะอาดกว่า ปัญหาคือตอนนี้ซีเควนเซอร์ของฉันไม่ได้ทำงานบนเธรดเดียวกันเสมอไป เธรดที่ใช้งานอยู่สามารถเปลี่ยนแปลงได้ในระหว่างการโทรกลับ ดังนั้นจึงไม่ใช่เรื่องง่ายอีกต่อไปที่จะตัดสินว่าฉันอยู่ในบริบทที่ถูกต้องเพื่อดำเนินการต่อไปหรือไม่ สิ่งหนึ่งที่ควรทราบก็คือ การดำเนินการบางอย่างนั้นประกอบด้วยการรอคอย ซึ่งหมายความว่าทั้งลำดับและการดำเนินการแต่ละรายการสามารถขยายได้หลายเธรด

คำถามของฉัน: มีใครทราบรูปแบบที่ดีในการจัดการกับการรับสิทธิ์การเข้าถึงแบบเอกสิทธิ์เฉพาะบุคคลเมื่อมีการสลับเธรดเนื่องจาก async/await หรือไม่

เพื่อการอ้างอิง บางสิ่งที่ฉันได้พิจารณา:

  1. ฉันสามารถสร้าง SynchronizationContext แบบกำหนดเองที่รวบรวมการเรียกซีเควนเซอร์ทั้งหมดในช่วงเวลาของลำดับกลับไปยังเธรดเดียว สิ่งนี้มีประโยชน์ในการอนุญาตให้ฉันนำรหัสการจัดการการเข้าถึงความสัมพันธ์ของเธรดที่มีอยู่กลับมาใช้ใหม่ได้ ข้อเสียคือจะต้องทุ่มเทเธรดทุกครั้งที่ฉันทำลำดับหรือการดำเนินการ (เนื่องจากการดำเนินการสามารถขยายหลายเธรดได้)

  2. สร้างโทเค็นการเข้าถึงที่สามารถรับได้เพื่อส่งผ่านไปยังวิธีดำเนินการเพื่อพิสูจน์ว่าคุณได้รับสิทธิ์การเข้าถึง นี่เป็นข้อเสียของการบวมวิธีการด้วยพารามิเตอร์โทเค็น

  3. ใช้วิธีการโทเค็นการเข้าถึงจาก (2) แต่สร้างการใช้งานอินเทอร์เฟซที่ซ้ำกันสำหรับอินเทอร์เฟซการดำเนินงานเพื่อให้สามารถสร้าง wrapper ได้ทันทีด้วยโทเค็น 'baked-in' สิ่งนี้จะสร้างโค้ดกาวที่น่าเกลียด แต่จะล้างโค้ดซีเควนเซอร์เพื่อไม่ให้ต้องส่งโทเค็นไปยังแต่ละวิธีอีกต่อไป


person Dan Bryant    schedule 02.10.2012    source แหล่งที่มา


คำตอบ (2)


คำถามของฉัน: มีใครทราบรูปแบบที่ดีในการจัดการกับการรับสิทธิ์การเข้าถึงแบบเอกสิทธิ์เฉพาะบุคคลเมื่อมีการสลับเธรดเนื่องจาก async/await หรือไม่

ได้ คุณสามารถใช้ AsyncLock ได้ ซึ่งก็คือ ยังมีให้บริการโดยเป็นส่วนหนึ่งของ ไลบรารี AsyncEx ของฉันด้วย หากคุณต้องการมีการดำเนินการแบบ "TryLock" คุณอาจต้องสร้างการดำเนินการดั้งเดิมของคุณเอง

คุณจะสูญเสียความสามารถในการตรวจสอบความปลอดภัยบางส่วน: ไม่มีวิธีใดที่จะตรวจสอบได้ว่าเธรดที่กำลังดำเนินการอยู่นั้นมี AsyncLock เฉพาะเจาะจงหรือไม่

ตัวเลือกอื่นๆ ได้แก่ ConcurrentExclusiveSchedulerPair (ซึ่งฉันบล็อกเกี่ยวกับที่นี่) หรือ TPL Dataflow

person Stephen Cleary    schedule 02.10.2012
comment
ฉันจะทำเครื่องหมายนี้เป็นคำตอบสำหรับการอ่านที่เป็นประโยชน์ ในที่สุดฉันก็สร้างพรอกซีสำหรับอินเทอร์เฟซที่มีการตรวจสอบการเข้าถึง จากนั้น ฉันสามารถแจกพร็อกซี 'การเข้าถึงพิเศษ' แบบใช้แล้วทิ้งแบบพิเศษได้ ซึ่งจะป้องกันไม่ให้อินสแตนซ์พร็อกซีอื่นๆ ใช้ระบบในขณะที่ยังมีชีวิตอยู่ - person Dan Bryant; 06.10.2012

มี SemaphoreSlim.WaitAsync ซึ่งเข้ากันได้พอดีที่นี่ (ฉันพบมันในคำถามที่คล้ายกัน)

person bohdan_trotsenko    schedule 16.11.2015