. صافي:كيف يمكنني استدعاء مندوب على موضوع معين?(إيسينكرونيزينفوك ، المرسل ، أسينكوبيراتيون ، سينكرينيزاتيونكونتيكست ، الخ.)

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

سؤال

لاحظ أولا أن هذا السؤال لم يتم وضع علامة عليه أو أو أي شيء آخر واجهة المستخدم الرسومية محددة.هذا مقصود ، كما سترى قريبا.

ثانيا ، آسف إذا كان هذا السؤال طويلا إلى حد ما.أحاول تجميع أجزاء مختلفة من المعلومات التي تطفو هنا وهناك لتوفير معلومات قيمة أيضا.سؤالي ، ومع ذلك ، هو الحق تحت عنوان "ما أود أن أعرف".

أنا في مهمة لفهم أخيرا الطرق المختلفة التي تقدمها صافي لاستدعاء مندوب على موضوع معين.


ما أود أن أعرف:

  • أنا أبحث عن الطريقة الأكثر عمومية ممكنة (وهذا ليس وينفورمز أو وف محددة) لاستدعاء المندوبين على مواضيع محددة.

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


ما أعرفه بالفعل:

  • هناك العديد من الفصول المتعلقة بهذا الموضوع;من بينها:

    • SynchronizationContext (في System.Threading)
      إذا كان علي أن أخمن, سيكون هذا هو أبسط واحد;على الرغم من أنني لا أفهم بالضبط ما يفعله ، ولا كيف يتم استخدامه.

    • AsyncOperation & AsyncOperationManager (في System.ComponentModel)
      يبدو أن هذه أغلفة حولها SynchronizationContext.لا فكرة عن كيفية استخدامها.

    • WindowsFormsSynchronizationContext (في System.Windows.Forms)
      فئة فرعية من SynchronizationContext.

    • ISynchronizeInvoke (في System.ComponentModel)
      المستخدمة من قبل أشكال ويندوز.(ال Control الطبقة تنفذ هذا.إذا كان علي أن أخمن ، فأنا أقول إن هذا التنفيذ يستفيد من WindowsFormsSynchronizationContext.)

    • Dispatcher &DispatcherSynchronizationContext (في System.Windows.Threading)
      يبدو أن هذا الأخير هو فئة فرعية أخرى من SynchronizationContext, ، والمندوبين السابقين إليها.

  • تحتوي بعض سلاسل الرسائل على حلقة الرسائل الخاصة بها ، إلى جانب قائمة انتظار الرسائل.

    (صفحة مسن حول الرسائل وقوائم انتظار الرسائل لديه بعض المعلومات الأساسية التمهيدية حول كيفية عمل حلقات الرسائل على مستوى النظام ، أي.قوائم انتظار الرسائل مثل واجهة برمجة تطبيقات ويندوز.)

    أستطيع أن أرى كيف يمكن للمرء أن تنفيذ الاحتجاج عبر موضوع للخيوط مع قائمة انتظار الرسائل.باستخدام واجهة برمجة تطبيقات ويندوز ، يمكنك وضع رسالة في قائمة انتظار رسائل مؤشر ترابط معين عبر PostThreadMessage يحتوي على تعليمات لاستدعاء بعض المندوبين.حلقة الرسالة - التي تعمل على هذا الموضوع — سوف تحصل في نهاية المطاف إلى تلك الرسالة ، وسيتم استدعاء المندوب.

    من ما قرأت على مسن, ، لا يحتوي مؤشر الترابط تلقائيا على قائمة انتظار الرسائل الخاصة به.ستصبح قائمة انتظار الرسائل متاحة على سبيل المثال.عندما يخلق مؤشر ترابط نافذة.بدون قائمة انتظار الرسائل ، ليس من المنطقي أن يحتوي مؤشر الترابط على حلقة رسائل.

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

هل كانت مفيدة؟

المحلول

آسف لنشر مثل هذه الإجابة الطويلة.لكنني اعتقدت أن الأمر يستحق شرح ما يجري بالضبط.

أ-ها!أعتقد أنني قد حصلت عليه أحسب.يبدو أن الطريقة الأكثر عمومية لاستدعاء مندوب على مؤشر ترابط معين هي SynchronizationContext صف دراسي.

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

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

في ما يلي ، سأوضح كيفية تنفيذ قائمة انتظار الرسائل و SynchronizationContext لذلك ، فضلا عن موضوع مع حلقة رسالة.أخيرا ، سأوضح كيفية استدعاء مندوب في هذا الموضوع.


مثال:

الخطوة 1. دعونا أولا إنشاء SynchronizationContext فئة سيتم استخدام ذلك مع قائمة انتظار الرسائل في مؤشر الترابط المستهدف:

class QueueSyncContext : SynchronizationContext
{
    private readonly ConcurrentQueue<SendOrPostCallback> queue;

    public QueueSyncContext(ConcurrentQueue<SendOrPostCallback> queue)
    {
        this.queue = queue;
    }

    public override void Post(SendOrPostCallback d, object state)
    {
        queue.Enqueue(d);
    }

    // implementation for Send() omitted in this example for simplicity's sake.
}

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

الخطوة 2. دعونا الآن كتابة رمز لموضوع Z الذي ينتظر المندوبين d للوصول:

SynchronizationContext syncContextForThreadZ = null;

void MainMethodOfThreadZ()
{
    // this will be used as the thread's message queue:
    var queue = new ConcurrentQueue<PostOrCallDelegate>();

    // set up a synchronization context for our message processing:
    syncContextForThreadZ = new QueueSyncContext(queue);
    SynchronizationContext.SetSynchronizationContext(syncContextForThreadZ);

    // here's the message loop (not efficient, this is for demo purposes only:)
    while (true)
    {
        PostOrCallDelegate d = null;
        if (queue.TryDequeue(out d))
        {
            d.Invoke(null);
        }
    }
}

الخطوة 3. الموضوع Z يجب أن تبدأ في مكان ما:

new Thread(new ThreadStart(MainMethodOfThreadZ)).Start();

الخطوة 4. وأخيرا ، مرة أخرى على بعض الصفحات الأخرى A, ، نريد إرسال مندوب إلى الموضوع Z:

void SomeMethodOnThreadA()
{
    // thread Z must be up and running before we can send delegates to it:
    while (syncContextForThreadZ == null) ;

    syncContextForThreadZ.Post(_ =>
        {
            Console.WriteLine("This will run on thread Z!");
        },
        null);
}

الشيء الجميل في هذا هو أن SynchronizationContext يعمل ، بغض النظر عما إذا كنت في تطبيق نماذج ويندوز ، في تطبيق وف ، أو في تطبيق وحدة تحكم متعددة الخيوط من استنباط الخاصة بك.كل من وينفورمز و وف توفير وتثبيت مناسبة SynchronizationContextالصورة لموضوع الرئيسي / واجهة المستخدم.

الإجراء العام لاستدعاء مندوب على مؤشر ترابط معين هو ما يلي:

  • يجب عليك التقاط مؤشر الترابط الهدف (Z) SynchronizationContext, ، بحيث يمكنك Send (بشكل متزامن) أو Post (بشكل غير متزامن) مندوب إلى هذا الموضوع.طريقة كيفية القيام بذلك هي تخزين سياق المزامنة التي تم إرجاعها بواسطة SynchronizationContext.Current بينما كنت على موضوع الهدف Z.(يجب أن يكون سياق المزامنة هذا قد تم تسجيله مسبقا على / بواسطة مؤشر ترابط Z.) ثم قم بتخزين هذا المرجع في مكان ما حيث يمكن الوصول إليه عن طريق الخيط A.

  • بينما على الموضوع A, ، يمكنك استخدام سياق المزامنة الملتقطة لإرسال أو نشر أي مندوب إلى سلسلة الرسائل Z: zSyncContext.Post(_ => { ... }, null);

نصائح أخرى

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

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

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

يمكنك تنفيذ هذا بنفسك بسهولة كافية ، بما في ذلك في تطبيق وحدة التحكم.فقط تذكر أنه إذا كان مؤشر الترابط يدور حول قائمة انتظار العمل ، فلا يمكن أن يفعل شيئا آخر أيضا - في حين أن مؤشر الترابط الرئيسي للتنفيذ في تطبيق وحدة التحكم يهدف إلى تنفيذ سلسلة من المهام ثم الانتهاء.

صافي 4 ، فإنه من السهل جدا لتنفيذ قائمة انتظار المنتج / المستهلك باستخدام BlockingCollection صف دراسي.

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

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