تم تصميم نموذج سلاسل المحادثات في Binder لتسهيل استدعاء الدوال المحلية حتى إذا كانت هذه الاستدعاءات تتم في عملية بعيدة. وعلى وجه التحديد، يجب أن تتضمّن أي عملية تستضيف عقدة مجموعة من سلاسل ربط واحدة أو أكثر للتعامل مع المعاملات إلى العُقد المستضافة في تلك العملية.
المعاملات المتزامنة وغير المتزامنة
تتيح Binder إجراء معاملات متزامنة وغير متزامنة. توضّح الأقسام التالية كيفية تنفيذ كل نوع من أنواع المعاملات.
المعاملات المتزامنة
يتم حظر المعاملات المتزامنة إلى أن يتم تنفيذها على العقدة، ويتم تلقّي رد على تلك المعاملة من قِبل المتصل. يوضّح الشكل التالي كيفية تنفيذ معاملة متزامنة:
الشكل 1: معاملة متزامنة
لتنفيذ معاملة متزامنة، ينفّذ Binder ما يلي:
- تستدعي سلاسل المحادثات في مجموعة سلاسل المحادثات المستهدَفة (T2 وT3) برنامج تشغيل النواة لانتظار العمل الوارد.
- يتلقّى النواة معاملة جديدة ويوقظ سلسلة محادثات (T2) في العملية المستهدَفة للتعامل مع المعاملة.
- يتم حظر سلسلة التعليمات البرمجية التي تجري المكالمة (T1) والانتظار لتلقّي رد.
- تنفّذ العملية المستهدَفة المعاملة وتعرض ردًا.
- تستدعي السلسلة في العملية المستهدَفة (T2) برنامج تشغيل النواة مرة أخرى لانتظار عمل جديد.
المعاملات غير المتزامنة
لا تحظر المعاملات غير المتزامنة إكمالها، بل يتم إلغاء حظر سلسلة التعليمات التي تستدعيها بمجرد تمرير المعاملة إلى النواة. يوضّح الشكل التالي كيفية تنفيذ معاملة غير متزامنة:
الشكل 2: معاملة غير متزامنة
- تستدعي سلاسل المحادثات في مجمّع سلاسل المحادثات المستهدف (T2 وT3) برنامج تشغيل النواة لانتظار العمل الوارد.
- يتلقّى النواة معاملة جديدة ويوقظ سلسلة محادثات (T2) في العملية المستهدَفة للتعامل مع المعاملة.
- يستمر تنفيذ سلسلة التعليمات البرمجية التي يتم استدعاؤها (T1).
- تنفّذ العملية المستهدَفة المعاملة وتعرض ردًا.
- تستدعي السلسلة في العملية المستهدَفة (T2) برنامج تشغيل النواة مرة أخرى لانتظار عمل جديد.
تحديد دالة متزامنة أو غير متزامنة
الدوال التي تم وضع علامة oneway عليها في ملف AIDL هي دوال غير متزامنة. على سبيل المثال:
oneway void someCall();
إذا لم يتم وضع علامة oneway على دالة، ستكون دالة متزامنة، حتى إذا كانت الدالة تعرض void.
تسلسل المعاملات غير المتزامنة
تتولّى أداة الربط تسلسل المعاملات غير المتزامنة من أي عقدة واحدة. يوضّح الشكل التالي كيفية تسلسل معاملات غير متزامنة في Binder:
الشكل 3: تسلسل المعاملات غير المتزامنة
- تستدعي سلاسل المحادثات في مجمّع سلاسل المحادثات المستهدَف (B1 وB2) برنامج تشغيل النواة لانتظار العمل الوارد.
- يتم إرسال معاملتَين (T1 وT2) على العقدة نفسها (N1) إلى النواة.
- يتلقّى النواة معاملات جديدة، وبما أنّها واردة من العقدة نفسها (N1)، يتم تسلسلها.
- يتم إرسال معاملة أخرى على عقدة مختلفة (N2) إلى النواة.
- يتلقّى النواة المعاملة الثالثة ويوقظ سلسلة محادثات (B2) في العملية المستهدَفة للتعامل مع المعاملة.
- تنفّذ عمليات الاستهداف كل معاملة وتعرض ردًا.
المعاملات المتداخلة
يمكن أن تكون المعاملات المتزامنة متداخلة، ويمكن أن ينفّذ أحد سلاسل التنفيذ التي تعالج معاملة معاملة جديدة. يمكن أن تكون المعاملة المتداخلة إلى عملية مختلفة أو إلى العملية نفسها التي تلقّيت منها المعاملة الحالية. يحاكي هذا السلوك طلبات الدوال المحلية. على سبيل المثال، لنفترض أنّ لديك دالة تتضمّن دوالاً متداخلة:
def outer_function(x):
def inner_function(y):
def inner_inner_function(z):
إذا كانت هذه المكالمات محلية، يتم تنفيذها على سلسلة التعليمات البرمجية نفسها.
على وجه التحديد، إذا كان المتصل بـ inner_function هو أيضًا العملية التي تستضيف العقدة التي تنفّذ inner_inner_function، يتم تنفيذ طلب inner_inner_function على سلسلة التعليمات البرمجية نفسها.
يوضّح الشكل التالي كيفية تعامل Binder مع المعاملات المتداخلة:
الشكل 4. المعاملات المتداخلة
- طلبات سلسلة المحادثات A1 الجارية
foo(). - كجزء من هذا الطلب، يتم تنفيذ السلسلة الفرعية B1 التي يتم تنفيذها في السلسلة الفرعية A1 نفسها.
bar()
يوضح الشكل التالي تنفيذ سلسلة التعليمات إذا كانت العقدة التي تنفذ
bar() في عملية مختلفة:
الشكل 5. المعاملات المتداخلة في عمليات مختلفة
- طلبات سلسلة المحادثات A1 الجارية
foo(). - كجزء من هذا الطلب، يتم تنفيذ السلسلة الفرعية B1 التي يتم تنفيذها في سلسلة فرعية أخرى C1.
bar()
يوضّح الشكل التالي كيف يعيد مؤشر الترابط استخدام العملية نفسها في أي مكان في سلسلة المعاملات:
الشكل 6. المعاملات المتداخلة التي تعيد استخدام سلسلة محادثات
- تتصل العملية (أ) بالعملية (ب).
- تتصل العملية B بالعملية C.
- بعد ذلك، ينفّذ العملية C عملية استدعاء إلى العملية A، ويعيد النواة استخدام سلسلة المحادثات A1 في العملية A التي تشكّل جزءًا من سلسلة المعاملات.
بالنسبة إلى المعاملات غير المتزامنة، لا يؤدي التداخل دورًا، لأنّ العميل لا ينتظر نتيجة المعاملة غير المتزامنة، وبالتالي لا يحدث تداخل. إذا كان معالج معاملة غير متزامنة يجري اتصالاً بالعملية التي أصدرت تلك المعاملة غير المتزامنة، يمكن معالجة تلك المعاملة على أي سلسلة محادثات غير مشغولة في تلك العملية.
تجنُّب حالات التعطّل
تعرض الصورة التالية حالة توقّف تام شائعة:
الشكل 7. التوقف التام الشائع
- تستخدم العملية A قفل الاستبعاد المتبادل MA وتجري طلبًا من خلال Binder (T1) إلى العملية B التي تحاول أيضًا استخدام قفل الاستبعاد المتبادل MB.
- في الوقت نفسه، يحصل العملية B على mutex MB ويُجري طلب binder (T2) إلى العملية A التي تحاول الحصول على mutex MA.
إذا تداخلت هاتان المعاملتان، يمكن أن تستخدم كل معاملة قفل استبعاد متبادل في عمليتها أثناء انتظار العملية الأخرى لإصدار قفل استبعاد متبادل، ما يؤدي إلى حدوث توقف تام.
لتجنُّب حالات التعطّل التام أثناء استخدام Binder، لا تحتفظ بأي قفل عند إجراء مكالمة Binder.
قواعد ترتيب عمليات القفل وحالات الانسداد
ضمن بيئة تنفيذ واحدة، يتم غالبًا تجنُّب حالة الجمود باستخدام قاعدة ترتيب الأقفال. ومع ذلك، عند إجراء عمليات استدعاء بين العمليات وبين قواعد الرموز، خاصةً عند تعديل الرموز، يصبح من المستحيل الحفاظ على قاعدة ترتيب وتنسيقها.
قفل استبعاد متبادل واحد وحالات توقّف تام
باستخدام المعاملات المتداخلة، يمكن للعملية B أن تعود مباشرةً إلى سلسلة المحادثات نفسها في العملية A التي تحتوي على mutex. لذلك، بسبب التكرار الحلقي غير المتوقّع، يظل من الممكن حدوث توقّف تام باستخدام قفل استبعاد متبادل واحد.
المكالمات غير المتزامنة وحالات الجمود
على الرغم من أنّ استدعاءات الرابط غير المتزامن لا تحظر الإكمال، يجب أيضًا تجنُّب الاحتفاظ بقفل للمكالمات غير المتزامنة. إذا كان لديك قفل، قد تواجه مشاكل في القفل إذا تم تغيير مكالمة أحادية الاتجاه عن طريق الخطأ إلى مكالمة متزامنة.
سلسلة ربط واحدة وحالات توقّف تام
يسمح نموذج المعاملات في Binder بإعادة الدخول، لذا حتى إذا كانت إحدى العمليات تتضمّن سلسلة Binder واحدة، سيظل عليك استخدام القفل. على سبيل المثال، لنفترض أنّك تكرّر قائمة في عملية ذات سلسلة محادثات واحدة، وهي العملية "أ". لكل عنصر في القائمة، عليك إجراء معاملة ربط صادرة. إذا كان تنفيذ الدالة التي تستدعيها ينشئ معاملة جديدة في Binder إلى عقدة مستضافة في العملية (أ)، يتم التعامل مع هذه المعاملة في سلسلة المحادثات نفسها التي كانت تتكرر في القائمة. إذا كان تنفيذ هذه المعاملة يعدّل القائمة نفسها، قد تواجه مشاكل عند مواصلة تكرار القائمة لاحقًا.
ضبط حجم مجموعة سلاسل التعليمات
عندما تتضمّن الخدمة عدة برامج، يمكن أن تؤدي إضافة المزيد من سلاسل المحادثات إلى مجموعة سلاسل المحادثات إلى تقليل التنازع وتقديم المزيد من المكالمات بالتوازي. بعد التعامل مع التزامن بشكل صحيح، يمكنك إضافة المزيد من سلاسل التعليمات. مشكلة يمكن أن تحدث بسبب إضافة المزيد من سلاسل المحادثات التي قد لا يتم استخدام بعضها أثناء أحمال العمل الهادئة
يتم إنشاء سلاسل المحادثات عند الطلب إلى أن يتم الوصول إلى الحد الأقصى الذي تم ضبطه. وبعد إنشاء سلسلة محادثات binder، تظل نشطة إلى أن تنتهي العملية التي تستضيفها.
تحتوي مكتبة libbinder على 15 سلسلة محادثات تلقائيًا. استخدِم
setThreadPoolMaxThreadCount لتغيير هذه القيمة:
using ::android::ProcessState;
ProcessState::self()->setThreadPoolMaxThreadCount(size_t maxThreads);