تجمع مؤشرات الترابط لتنفيذ مهام عشوائية ذات أولويات مختلفة

StackOverflow https://stackoverflow.com/questions/38501

  •  09-06-2019
  •  | 
  •  

سؤال

أحاول التوصل إلى تصميم لمجموعة مؤشرات الترابط مع الكثير من متطلبات التصميم لعملي.هذه مشكلة حقيقية لبرامج العمل، وهي مهمة صعبة.لدي تنفيذ عملي ولكني أود أن أطرح ذلك على SO وأرى ما هي الأفكار المثيرة للاهتمام التي يمكن أن يتوصل إليها الأشخاص، حتى أتمكن من مقارنتها بتطبيقي ومعرفة كيفية تكامله.لقد حاولت أن أكون محددًا للمتطلبات قدر الإمكان.

يحتاج تجمع مؤشرات الترابط إلى تنفيذ سلسلة من المهام.يمكن أن تكون المهام قصيرة المدى (أقل من ثانية واحدة) أو طويلة المدى (ساعات أو أيام).لكل مهمة أولوية مرتبطة بها (من 1 = منخفضة جدًا إلى 5 = عالية جدًا).يمكن أن تصل المهام في أي وقت أثناء تشغيل المهام الأخرى، لذلك عند وصولها، يحتاج تجمع سلاسل الرسائل إلى التقاطها وجدولتها عندما تصبح سلاسل الرسائل متاحة.

أولوية المهمة مستقلة تمامًا عن طول المهمة.في الواقع، من المستحيل معرفة المدة التي يمكن أن تستغرقها المهمة للتشغيل دون تشغيلها فقط.

بعض المهام مرتبطة بوحدة المعالجة المركزية (CPU) بينما بعضها مرتبط بشكل كبير بـ IO.من المستحيل معرفة المهمة المحددة مسبقًا (على الرغم من أنني أعتقد أنه قد يكون من الممكن اكتشافها أثناء تشغيل المهام).

الهدف الأساسي لتجمع الخيوط هو زيادة الإنتاجية إلى الحد الأقصى.يجب أن يستخدم تجمع مؤشرات الترابط موارد الكمبيوتر بشكل فعال.من الناحية المثالية، بالنسبة للمهام المرتبطة بوحدة المعالجة المركزية، سيكون عدد مؤشرات الترابط النشطة مساوياً لعدد وحدات المعالجة المركزية.بالنسبة للمهام المرتبطة بالإدخال/الإخراج، يجب تخصيص عدد أكبر من سلاسل العمليات مقارنة بوحدات المعالجة المركزية (CPUs) بحيث لا يؤثر الحظر بشكل مفرط على الإنتاجية.من المهم تقليل استخدام الأقفال واستخدام حاويات آمنة/سريعة الخيط.

بشكل عام، يجب عليك تشغيل المهام ذات الأولوية الأعلى مع أولوية أعلى لوحدة المعالجة المركزية (المرجع:تعيين أولوية الموضوع).يجب ألا "تمنع" المهام ذات الأولوية المنخفضة تشغيل المهام ذات الأولوية الأعلى، لذلك إذا ظهرت مهمة ذات أولوية أعلى أثناء تشغيل جميع المهام ذات الأولوية المنخفضة، فسيتم تشغيل المهمة ذات الأولوية الأعلى.

تحتوي المهام على معلمة "الحد الأقصى للمهام قيد التشغيل" المرتبطة بها.يُسمح فقط لكل نوع من المهام بتشغيل هذا العدد من المثيلات المتزامنة للمهمة في المرة الواحدة.على سبيل المثال، قد تكون لدينا المهام التالية في قائمة الانتظار:

  • أ - 1000 مثيل - أولوية منخفضة - الحد الأقصى للمهام 1
  • ب - 1000 مثيل - أولوية منخفضة - الحد الأقصى للمهام 1
  • ج - 1000 مثيل - أولوية منخفضة - الحد الأقصى للمهام 1

يمكن تنفيذ التنفيذ العملي فقط (على الأكثر) تشغيل 1 A و1 B و1 C في نفس الوقت.

يجب أن يعمل على أنظمة التشغيل Windows XP وServer 2003 وVista وServer 2008 (أحدث حزم الخدمة).


كمرجع، قد نستخدم الواجهة التالية:

namespace ThreadPool
{
    class Task
    {
    public:
        Task();     
        void run();
    };

    class ThreadPool
    {    
    public:
        ThreadPool();
        ~ThreadPool();

        void run(Task *inst);
        void stop();
    };
}
هل كانت مفيدة؟

المحلول

إذن ما الذي سنختاره باعتباره لبنة البناء الأساسية لذلك.يحتوي Windows على كتلتين أساسيتين تبدوان واعدتين: منافذ إكمال الإدخال/الإخراج (IOCPs) واستدعاءات الإجراءات غير المتزامنة (APCs).كلاهما يمنحنا قائمة انتظار FIFO دون الحاجة إلى إجراء قفل صريح، ومع قدر معين من دعم نظام التشغيل المدمج في أماكن مثل المجدول (على سبيل المثال، يمكن لـ IOCPs تجنب بعض مفاتيح تبديل السياق).

ربما تكون ناقلات الجنود المدرعة أكثر ملاءمة قليلاً، ولكن سيتعين علينا أن نكون حذرين قليلاً معها، لأنها ليست "شفافة" تمامًا.إذا أجرى عنصر العمل انتظارًا قابلاً للتنبيه (::SleepEx، ::WaitForXxxObjectEx، وما إلى ذلك) وقمنا بإرسال APC عن طريق الخطأ إلى مؤشر الترابط، فستتولى APC المرسلة حديثًا على مؤشر الترابط، مع تعليق APC الذي تم تنفيذه مسبقًا حتى يتم تشغيل APC الجديد انتهى.يعد هذا أمرًا سيئًا بالنسبة لمتطلبات التزامن الخاصة بنا ويمكن أن يزيد احتمالية حدوث تجاوزات في المكدس.

نصائح أخرى

يجب أن يعمل على أنظمة التشغيل Windows XP وServer 2003 وVista وServer 2008 (أحدث حزم الخدمة).

ما هي ميزة مجموعات مؤشرات الترابط المضمنة في النظام والتي تجعلها غير مناسبة لمهمتك؟إذا كنت تريد استهداف XP و2003، فلا يمكنك استخدام مجموعات Vista/2008 الجديدة اللامعة، ولكن لا يزال بإمكانك استخدام QueueUserWorkItem والأصدقاء.

@DrPizza - هذا سؤال جيد جدًا، وهو سؤال يضرب جوهر المشكلة مباشرةً.هناك عدة أسباب وراء استبعاد QueueUserWorkItem وتجمع مؤشرات الترابط لنظام التشغيل Windows NT (على الرغم من أن نظام التشغيل Vista يبدو مثيرًا للاهتمام، ربما في غضون سنوات قليلة).

أولاً، أردنا أن يكون لدينا تحكم أكبر في وقت بدء تشغيل الخيوط وإيقافها.لقد سمعنا أن تجمع مؤشرات الترابط NT يتردد في بدء مؤشر ترابط جديد إذا كان يعتقد أن المهام قصيرة المدى.يمكننا استخدام الدالة WT_EXECUTELONGFUNCTION، لكن ليس لدينا أي فكرة عما إذا كانت المهمة طويلة أم قصيرة

ثانيًا، إذا كان تجمع مؤشرات الترابط ممتلئًا بالفعل بمهام طويلة الأمد وذات أولوية منخفضة، فلن تكون هناك فرصة لتشغيل مهمة ذات أولوية عالية في الوقت المناسب.لا يحتوي تجمع مؤشرات الترابط NT على مفهوم حقيقي لأولويات المهمة، لذلك لا يمكننا تنفيذ QueueUserWorkItem والقول "أوه بالمناسبة، قم بتشغيل هذا على الفور".

ثالثًا، (وفقًا لـ MSDN) تجمع مؤشرات الترابط NT غير متوافق مع طراز الشقة STA.لست متأكدًا تمامًا مما يعنيه هذا، ولكن جميع سلاسل العمليات العاملة لدينا تعمل في STA.

@DrPizza - هذا سؤال جيد جدًا، وهو سؤال يضرب جوهر المشكلة مباشرةً.هناك عدة أسباب وراء استبعاد QueueUserWorkItem وتجمع مؤشرات الترابط لنظام التشغيل Windows NT (على الرغم من أن نظام التشغيل Vista يبدو مثيرًا للاهتمام، ربما في غضون سنوات قليلة).

نعم، يبدو أنه تم تعزيزه تمامًا في نظام التشغيل Vista، وهو متعدد الاستخدامات الآن.

حسنًا، ما زلت غير واضح بعض الشيء بشأن الطريقة التي تريد أن تعمل بها الأولويات.إذا كان التجمع يقوم حاليًا بتشغيل مهمة من النوع A مع أقصى قدر من التزامن 1 وأولوية منخفضة، وتم منحه مهمة جديدة أيضًا من النوع A (والتزامن الأقصى 1)، ولكن هذه المرة بأولوية عالية، فماذا يجب أن يفعل ؟

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

افتراضاتي هي أن هذا هو السلوك الأخير الذي تبحث عنه؟

@دكتوربيتزا:

حسنًا ، ما زلت غير واضح بعض الشيء حول كيفية رغبتك في أولويات العمل.إذا كان المجمع يدير حاليًا مهمة من النوع A مع الحد الأقصى للتزامن بأولوية 1 ومنخفضة الأولوية ، ويتم إعطاؤه مهمة جديدة أيضًا من النوع A (والتزامن القصوى 1) ، ولكن هذه المرة بأولوية عالية ، ما الذي يجب عليه فعله ؟

هذه المهمة صعبة بعض الشيء، على الرغم من أنني أعتقد في هذه الحالة أنني سأكون سعيدًا بمجرد السماح للمهمة ذات الأولوية المنخفضة بالاستمرار حتى الاكتمال.عادةً، لن نرى الكثير من نفس أنواع المهام ذات أولويات سلاسل مختلفة.في نموذجنا، من الممكن بالفعل إيقاف المهام بأمان ثم إعادة تشغيلها لاحقًا عند نقاط معينة محددة جيدًا (لأسباب مختلفة عن هذه) على الرغم من أن المضاعفات التي قد يقدمها هذا ربما لا تستحق المخاطرة.

عادةً ما تكون للأنواع المختلفة من المهام أولويات مختلفة.على سبيل المثال:

  • مهمة - 1000 حالة - أولوية منخفضة
  • المهمة ب - 1000 حالة - أولوية عالية

بافتراض أن المهام A قد جاءت وكانت قيد التشغيل، ثم وصلت المهام B، فإننا نرغب في أن تكون المهام B قادرة على التشغيل بشكل أو بآخر على الفور.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top