هل هذا خطأ في عبارة مراقبة / قفل .NET أو هل يتصرف MessageBox.Show بشكل مختلف؟

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

  •  06-09-2019
  •  | 
  •  

سؤال

تخيل أن لديك اثنين من الأزرار على شكل الفوز. ما رأيك يجب أن يكون السلوك عندما يضغط المستخدم على "الزر 1" مع الرمز أدناه؟

يجب أن يعرض كل مربع رسالة 5 في Go One، أو One by One - MessageBox.Show بيان داخل بيان القفل؟

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private static readonly object lockobject = new object();

    private void button1_Click(object sender, EventArgs e)
    {
        var action = new Action(function);
        for(int i = 0; i< 5; i++)
        {
            action.BeginInvoke(null, null);
        }
    }

    private void function()
    {
        if (button2.InvokeRequired)
        {
            var func = new Action(function);
            button2.Invoke(func);
        }
        else
        {
            lock (lockobject)
            {
                MessageBox.Show("Testing");
            }
        }
    }
}

الآن إذا استبدلنا MessageBox.Show مع أي إصدار آخر، فسوف ينفذ العبارة واحدة فقط في كل مرة، فإن المواضيع الأخرى ستنتظر، واحدة في كل مرة.

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

المحلول

نظرا لأن بيان القفل الخاص بك يتم تنفيذها عند عدم وجود invokerequired FALSE، فسيتم تشغيل الأقفال جميعها على نفس الخيط (الرئيسي). لذلك لن تغلق الأقفال.

إذا كنت تريد حظر MessageBox، استخدم ShowDialog بدلا من ذلك.

نصائح أخرى

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

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

نظرا لأن 2 الكود الخاص بك ليس متعدد الخيوط على الإطلاق، فإن كل شيء ينفذ في نفس الخيط - وهذا يعيدنا إلى 1، عندما لا يكون لديك قفل خيوط متعددة لا يفعل شيئا.

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

يمكنك منعها بقوة أكبر، ولكن من شأنه أن يمنع اللوحة ("لا يستجيب" إلخ).

وأنا أتفق مع نير. بعد تغيير وظيفتك إلى الواحدة أدناه، يمكنك اختبار أنك تعمل على نفس مؤشر الترابط (وليس من المستغرب):

private void function()
{
   if (button2.InvokeRequired)
   {
        var func = new Action(function);
        button2.Invoke(func);
   }
   else
   {
        lock (lockobject)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            MessageBox.Show("Testing. Running on thread "+threadId);
        }
    }
}

حتى هنا لأن خيط UI الخاص بك بسبب القفل، لا يتم حظره. خلاصة القول هي أن مؤشرات الترابط STA غير متوافقة مع البرمجة المناسبة متعددة المراحل.

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