التعامل مع سلاسل المحادثات

تم تصميم نموذج سلاسل المحادثات في Binder لتسهيل استدعاء الدوال المحلية حتى إذا كانت هذه الاستدعاءات تتم في عملية بعيدة. وعلى وجه التحديد، يجب أن تتضمّن أي عملية تستضيف عقدة مجموعة من سلاسل ربط واحدة أو أكثر للتعامل مع المعاملات إلى العُقد المستضافة في تلك العملية.

المعاملات المتزامنة وغير المتزامنة

تتيح Binder إجراء المعاملات المتزامنة وغير المتزامنة. توضّح الأقسام التالية كيفية تنفيذ كل نوع من أنواع المعاملات.

المعاملات المتزامنة

يتم حظر المعاملات المتزامنة إلى أن يتم تنفيذها على العقدة، ويتلقّى المتصل ردًا على تلك المعاملة. يوضّح الشكل التالي كيفية تنفيذ معاملة متزامنة:

معاملة متزامنة

الشكل 1. معاملة متزامنة

لتنفيذ معاملة متزامنة، ينفّذ Binder ما يلي:

  1. تستدعي سلاسل المحادثات في مجمّع سلاسل المحادثات المستهدف (T2 وT3) برنامج تشغيل النواة لانتظار العمل الوارد.
  2. يتلقّى النواة معاملة جديدة ويوقظ سلسلة محادثات (T2) في العملية المستهدَفة للتعامل مع المعاملة.
  3. يتم حظر سلسلة استدعاء الدوال البرمجية (T1) والانتظار لتلقّي رد.
  4. تنفّذ العملية المستهدَفة المعاملة وتعرض ردًا.
  5. يطلب مؤشر الترابط في العملية المستهدَفة (T2) من برنامج تشغيل النواة معاودة الاتصال لانتظار عمل جديد.

المعاملات غير المتزامنة

لا تحظر المعاملات غير المتزامنة إكمالها، بل يتم إلغاء حظر سلسلة التعليمات التي يتم استدعاؤها بمجرد تمرير المعاملة إلى النواة. يوضّح الشكل التالي كيفية تنفيذ معاملة غير متزامنة:

معاملة غير متزامنة

الشكل 2. معاملة غير متزامنة

  1. تستدعي سلاسل المحادثات في مجمّع سلاسل المحادثات المستهدف (T2 وT3) برنامج تشغيل النواة لانتظار العمل الوارد.
  2. يتلقّى النواة معاملة جديدة ويوقظ سلسلة محادثات (T2) في العملية المستهدَفة للتعامل مع المعاملة.
  3. يستمر تنفيذ سلسلة استدعاء الدوال البرمجية (T1).
  4. تنفّذ العملية المستهدَفة المعاملة وتعرض ردًا.
  5. يطلب مؤشر الترابط في العملية المستهدَفة (T2) من برنامج تشغيل النواة معاودة الاتصال لانتظار عمل جديد.

تحديد دالة متزامنة أو غير متزامنة

الدوال التي تم وضع علامة oneway عليها في ملف AIDL هي دوال غير متزامنة. مثلاً:

oneway void someCall();

إذا لم يتم وضع علامة oneway على دالة، ستكون دالة متزامنة، حتى إذا كانت الدالة تعرض void.

تسلسل المعاملات غير المتزامنة

تتولّى أداة الربط تسلسل المعاملات غير المتزامنة من أي عقدة واحدة. يوضِّح الشكل التالي كيفية تسلسل عمليات النقل غير المتزامنة في Binder:

تسلسل المعاملات غير المتزامنة

الشكل 3. تسلسل المعاملات غير المتزامنة

  1. تستدعي سلاسل المحادثات في مجمّع سلاسل المحادثات المستهدف (B1 وB2) برنامج تشغيل النواة لانتظار العمل الوارد.
  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 التي يتم تنفيذها في السلسلة الفرعية A1 نفسها.bar()

يوضح الشكل التالي تنفيذ سلسلة التعليمات إذا كانت العقدة التي تنفّذ bar() في عملية مختلفة:

المعاملات المتداخلة في عمليات مختلفة

الشكل 5. المعاملات المتداخلة في عمليات مختلفة

  1. طلبات سلسلة المحادثات A1 التي يتم تنفيذها foo().
  2. كجزء من هذا الطلب، يتم تنفيذ السلسلة الفرعية B1 التي تنفذ bar() في سلسلة فرعية أخرى C1.

يوضّح الشكل التالي كيف يعيد مؤشر الترابط استخدام العملية نفسها في أي مكان في سلسلة المعاملات:

المعاملات المتداخلة التي تعيد استخدام سلسلة محادثات

الشكل 6. المعاملات المتداخلة التي تعيد استخدام سلسلة محادثات

  1. تتصل العملية (أ) بالعملية (ب).
  2. تتصل العملية "ب" بالعملية "ج".
  3. بعد ذلك، ينفّذ العملية C عملية استدعاء إلى العملية A، ويعيد النواة استخدام السلسلة الفرعية A1 في العملية A التي تشكّل جزءًا من سلسلة المعاملات.

بالنسبة إلى المعاملات غير المتزامنة، لا يكون للتداخل أي دور، لأنّ العميل لا ينتظر نتيجة المعاملة غير المتزامنة، وبالتالي لا يكون هناك تداخل. إذا كان معالج معاملة غير متزامنة يجري طلبًا في العملية التي أصدرت تلك المعاملة غير المتزامنة، يمكن معالجة تلك المعاملة على أي سلسلة محادثات غير مشغولة في تلك العملية.

تجنُّب حالات التعطّل

تعرض الصورة التالية حالة توقّف تام شائعة:

التعطّل الشائع

الشكل 7. التعطّل الشائع

  1. يستحوذ العملية A على mutex MA وتجري عملية ربط (T1) مع العملية B التي تحاول أيضًا الاستحواذ على mutex MB.
  2. في الوقت نفسه، يحصل العملية 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);