จัดการชุดข้อความ

รูปแบบการทำงานของ Binder ได้รับการออกแบบมาเพื่ออำนวยความสะดวกในการเรียกฟังก์ชันในเครื่อง แม้ว่าการเรียกเหล่านั้นอาจเป็นการเรียกไปยังกระบวนการระยะไกลก็ตาม กล่าวคือ กระบวนการใดๆ ที่โฮสต์โหนดต้องมีพูลของเธรด Binder อย่างน้อย 1 รายการเพื่อจัดการธุรกรรมไปยังโหนดที่โฮสต์ในกระบวนการนั้น

ธุรกรรมแบบซิงโครนัสและแบบอะซิงโครนัส

Binder รองรับธุรกรรมแบบซิงโครนัสและอะซิงโครนัส ส่วนต่อไปนี้จะอธิบายวิธีดำเนินการธุรกรรมแต่ละประเภท

ธุรกรรมแบบซิงโครนัส

ธุรกรรมแบบซิงโครนัสจะบล็อกจนกว่าจะมีการดำเนินการในโหนด และผู้เรียกจะได้รับ การตอบกลับสำหรับธุรกรรมนั้น รูปต่อไปนี้ แสดงวิธีดำเนินการธุรกรรมแบบซิงโครนัส

ธุรกรรมแบบซิงโครนัส

รูปที่ 1 ธุรกรรมแบบซิงโครนัส

หากต้องการดำเนินการธุรกรรมแบบซิงโครนัส Binder จะทำสิ่งต่อไปนี้

  1. เธรดใน Threadpool เป้าหมาย (T2 และ T3) จะเรียกใช้เคอร์เนล ไดรเวอร์เพื่อรอการทำงานที่เข้ามา
  2. เคอร์เนลจะได้รับการทำธุรกรรมใหม่และปลุกเธรด (T2) ใน กระบวนการเป้าหมายเพื่อจัดการธุรกรรม
  3. เธรดการเรียก (T1) จะบล็อกและรอการตอบกลับ
  4. กระบวนการเป้าหมายจะดำเนินการธุรกรรมและส่งคืนการตอบกลับ
  5. เธรดในกระบวนการเป้าหมาย (T2) จะเรียกกลับไปที่ไดรเวอร์เคอร์เนลเพื่อ รอการทำงานใหม่

ธุรกรรมแบบอะซิงโครนัส

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

ธุรกรรมแบบอะซิงโครนัส

รูปที่ 2 ธุรกรรมแบบอะซิงโครนัส

  1. เธรดใน Threadpool เป้าหมาย (T2 และ T3) จะเรียกใช้เคอร์เนล ไดรเวอร์เพื่อรอการทำงานที่เข้ามา
  2. เคอร์เนลจะได้รับการทำธุรกรรมใหม่และปลุกเธรด (T2) ใน กระบวนการเป้าหมายเพื่อจัดการธุรกรรม
  3. เธรดการเรียก (T1) จะดำเนินการต่อไป
  4. กระบวนการเป้าหมายจะดำเนินการธุรกรรมและส่งคืนการตอบกลับ
  5. เธรดในกระบวนการเป้าหมาย (T2) จะเรียกกลับไปที่ไดรเวอร์เคอร์เนลเพื่อ รอการทำงานใหม่

ระบุฟังก์ชันแบบซิงโครนัสหรืออะซิงโครนัส

ฟังก์ชันที่ทำเครื่องหมายเป็น oneway ในไฟล์ AIDL จะเป็นแบบไม่พร้อมกัน เช่น

oneway void someCall();

หากไม่ได้ทำเครื่องหมายฟังก์ชันเป็น oneway ฟังก์ชันนั้นจะเป็นฟังก์ชันแบบซิงโครนัส แม้ว่าฟังก์ชันจะแสดงผล void ก็ตาม

การทำให้ธุรกรรมแบบอะซิงโครนัสเป็นแบบอนุกรม

Binder จะทำการซีเรียลไลซ์ธุรกรรมแบบไม่พร้อมกันจากโหนดเดียว รูปภาพต่อไปนี้แสดงวิธีที่ Binder ทำให้ธุรกรรมแบบอะซิงโครนัสเป็นอนุกรม

การทำให้ธุรกรรมแบบอะซิงโครนัสเป็นแบบอนุกรม

รูปที่ 3 การทำให้ธุรกรรมแบบอะซิงโครนัสเป็นแบบอนุกรม

  1. เธรดใน Threadpool เป้าหมาย (B1 และ B2) จะเรียกใช้เคอร์เนล ไดรเวอร์เพื่อรอการทำงานที่เข้ามา
  2. ระบบจะส่งธุรกรรม 2 รายการ (T1 และ T2) ในโหนดเดียวกัน (N1) ไปยังเคอร์เนล
  3. เคอร์เนลจะได้รับธุรกรรมใหม่และจัดลำดับธุรกรรมเหล่านั้นเนื่องจากมาจากโหนดเดียวกัน (N1)
  4. ระบบจะส่งธุรกรรมอื่นในโหนดอื่น (N2) ไปยังเคอร์เนล
  5. เคอร์เนลจะได้รับธุรกรรมที่สามและปลุกเธรด (B2) ใน กระบวนการเป้าหมายเพื่อจัดการธุรกรรม
  6. กระบวนการเป้าหมายจะดำเนินการธุรกรรมแต่ละรายการและส่งคืนการตอบกลับ

ธุรกรรมที่ซ้อนกัน

ธุรกรรมแบบซิงโครนัสสามารถซ้อนกันได้ โดยเธรดที่จัดการธุรกรรมจะออกธุรกรรมใหม่ได้ ธุรกรรมที่ซ้อนกันอาจเป็นธุรกรรมที่ส่งไปยัง กระบวนการอื่น หรือกระบวนการเดียวกันกับที่คุณได้รับธุรกรรมปัจจุบัน ลักษณะการทำงานนี้เลียนแบบการเรียกใช้ฟังก์ชันในเครื่อง ตัวอย่างเช่น สมมติว่าคุณมีฟังก์ชันที่มีฟังก์ชันซ้อนกันดังนี้

def outer_function(x):
    def inner_function(y):
        def inner_inner_function(z):

หากเป็นการเรียกใช้ในเครื่อง ระบบจะดำเนินการในเธรดเดียวกัน กล่าวคือ หากผู้เรียกของ inner_function เป็นกระบวนการ ที่โฮสต์โหนดที่ใช้ inner_inner_function ด้วย การเรียกไปยัง inner_inner_function จะดำเนินการในเธรดเดียวกัน

รูปภาพต่อไปนี้แสดงวิธีที่ Binder จัดการธุรกรรมที่ซ้อนกัน

ธุรกรรมที่ซ้อนกัน

รูปที่ 4 ธุรกรรมที่ซ้อนกัน

  1. เทรด A1 ขอให้เรียกใช้ foo()
  2. ในส่วนของคำขอนี้ เทรด B1 จะเรียกใช้ bar() ซึ่ง A จะเรียกใช้ในเทรด A1 เดียวกัน

รูปต่อไปนี้แสดงการดำเนินการของเธรดหากโหนดที่ใช้ bar() อยู่ในกระบวนการอื่น

ธุรกรรมที่ซ้อนกันในกระบวนการต่างๆ

รูปที่ 5 ธุรกรรมที่ซ้อนกันในกระบวนการต่างๆ

  1. เทรด A1 ขอให้เรียกใช้ foo()
  2. ในส่วนของคำขอนี้ เทรด B1 จะเรียกใช้ bar() ซึ่งทำงานในเทรด C1 อีกเทรดหนึ่ง

รูปต่อไปนี้แสดงวิธีที่เธรดนำกระบวนการเดียวกันกลับมาใช้ซ้ำได้ทุกที่ใน ห่วงโซ่ธุรกรรม

ธุรกรรมที่ซ้อนกันซึ่งใช้เธรดซ้ำ

รูปที่ 6 ธุรกรรมที่ซ้อนกันซึ่งใช้เธรดซ้ำ

  1. กระบวนการ A โทรหากระบวนการ B
  2. กระบวนการ B เรียกใช้กระบวนการ C
  3. จากนั้นกระบวนการ C จะโทรกลับไปยังกระบวนการ A และเคอร์เนล จะใช้เธรด A1 ในกระบวนการ A ซึ่งเป็นส่วนหนึ่งของห่วงโซ่ธุรกรรมซ้ำ

สำหรับการทำธุรกรรมแบบไม่พร้อมกัน การซ้อนจะไม่เกี่ยวข้อง เนื่องจากไคลเอ็นต์ไม่ต้องรอผลลัพธ์ของธุรกรรมแบบไม่พร้อมกัน จึงไม่มีการซ้อน หากตัวแฮนเดิลของธุรกรรมแบบอะซิงโครนัสเรียกใช้กระบวนการที่ออกธุรกรรมแบบอะซิงโครนัส ธุรกรรมนั้นจะได้รับการจัดการในเธรดว่างในกระบวนการนั้น

หลีกเลี่ยงการเกิดภาวะหยุดชะงัก

รูปภาพต่อไปนี้แสดงการเกิดภาวะหยุดชะงักที่พบบ่อย

ภาวะหยุดชะงักที่พบบ่อย

รูปที่ 7 ภาวะหยุดชะงักที่พบบ่อย

  1. กระบวนการ A ใช้ Mutex MA และทำการเรียก Binder (T1) ไปยัง กระบวนการ B ซึ่งพยายามใช้ Mutex MB ด้วย
  2. ในขณะเดียวกัน กระบวนการ B จะใช้ Mutex MB และทำการเรียกใช้ Binder (T2) ไปยัง กระบวนการ A ซึ่งพยายามใช้ Mutex MA

หากธุรกรรมเหล่านี้ทับซ้อนกัน ธุรกรรมแต่ละรายการอาจใช้ mutex ในกระบวนการของตนเองขณะรอให้กระบวนการอื่นปล่อย mutex ซึ่งส่งผลให้เกิดการหยุดชะงัก

หากต้องการหลีกเลี่ยงการหยุดชะงักขณะใช้ Binder อย่าถือล็อกใดๆ เมื่อทำการเรียก Binder

กฎการเรียงลำดับการล็อกและภาวะหยุดชะงัก

ภายในสภาพแวดล้อมการดำเนินการเดียว มักจะหลีกเลี่ยงการเกิดภาวะหยุดชะงักด้วย กฎการจัดลำดับการล็อก อย่างไรก็ตาม เมื่อทำการเรียกใช้ระหว่างกระบวนการและระหว่างโค้ดเบส โดยเฉพาะอย่างยิ่งเมื่อมีการอัปเดตโค้ด การรักษากฎการเรียงลำดับและการประสานงานจึงเป็นไปไม่ได้

Mutex เดียวและการเกิด Deadlock

เมื่อใช้ธุรกรรมที่ซ้อนกัน กระบวนการ B จะเรียกกลับไปยังเธรดเดียวกันในกระบวนการ A ที่ถือ Mutex ได้โดยตรง ดังนั้น การเรียกซ้ำที่ไม่คาดคิดอาจทำให้เกิดภาวะหยุดชะงักด้วย Mutex เดียวได้

การเรียกแบบซิงโครนัสและภาวะหยุดชะงัก

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

เธรด Binder เดียวและภาวะหยุดชะงัก

โมเดลธุรกรรมของ Binder อนุญาตให้มีการเรียกซ้ำ ดังนั้นแม้ว่ากระบวนการจะมี เธรด Binder เดียว คุณก็ยังต้องใช้การล็อก เช่น สมมติว่าคุณกำลัง วนซ้ำในรายการในกระบวนการแบบเธรดเดียว A สำหรับแต่ละรายการใน list คุณจะทำธุรกรรมการโอน หากการใช้งานฟังก์ชันที่คุณเรียกใช้สร้างธุรกรรม Binder ใหม่ไปยังโหนดที่โฮสต์ในกระบวนการ A ระบบจะจัดการธุรกรรมนั้นในเธรดเดียวกันกับที่วนซ้ำรายการ หากการติดตั้งใช้งานธุรกรรมนั้นแก้ไขรายการเดียวกัน คุณอาจพบปัญหาเมื่อทำซ้ำรายการในภายหลัง

กำหนดค่าขนาด Threadpool

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

ระบบจะสร้างเธรดตามต้องการจนกว่าจะถึงจำนวนสูงสุดที่กำหนดค่าไว้ หลังจากสร้างเธรด Binder แล้ว เธรดจะยังคงทำงานอยู่จนกว่ากระบวนการที่โฮสต์เธรดจะสิ้นสุดลง

ไลบรารี libbinder มีค่าเริ่มต้นเป็น 15 เธรด ใช้ setThreadPoolMaxThreadCount เพื่อเปลี่ยนค่านี้

using ::android::ProcessState;
ProcessState::self()->setThreadPoolMaxThreadCount(size_t maxThreads);