سؤال

NENT's الدلالات الغريبة قفل هي التي تنقلني مرة أخرى.

أنا أطلق موضوعا، يبدأ مؤشر الترابط في المنعطفات نموذجا. يجب أن ينتظر الخيط الأم حتى يتم إنشاء النموذج.

كانت محاولتي الأولى هي استخدام شاشة لمشاهدة متغير النموذج:

private void OpenForm()
{
    if (FormThread == null)
    {
        Monitor.Enter(Form);
        FormThread = new Thread(FormStub);
        FormThread.SetApartmentState(ApartmentState.STA);
        FormThread.Start();
        Monitor.Wait(Form);
        Monitor.Exit(Form);
    }
}

private void FormStub()
{
    Form = new ConnectorForm();
    Monitor.Enter(Form);
    Monitor.PulseAll(Form);
    Monitor.Exit(Form);
    Application.Run(Form);
}

... هذا يلقي استثناء. فشل monitor.enter ()، منذ النموذج == null.

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

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

المحلول

أفضل مزامنة البدائية لهذه العلبة:

private ManualResetEvent mre = new ManualResetEvent(false);

private void OpenForm()
{
    if (FormThread == null)
    {
        FormThread = new Thread(FormStub);
        FormThread.SetApartmentState(ApartmentState.STA);
        FormThread.Start();
        mre.WaitOne();
    }
}

private void FormStub()
{
    Form = new ConnectorForm();
    mre.Set();
    Application.Run(Form);
}

نصائح أخرى

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

يمكنك تجربة ما يلي، والذي يستخدم واحد object/Monitor كآلية الرسائل:

private void OpenForm()
{
    if (FormThread == null)
    {
        object obj = new object();
        lock (obj)
        {
            FormThread = new Thread(delegate () {
                lock (obj)
                {
                    Form = new ControllerForm();
                    Monitor.Pulse(obj);
                }
                Application.Run(Form);
            });
            FormThread.SetApartmentState(ApartmentState.STA);
            FormThread.Start();
            Monitor.Wait(obj);
        }
    }
}

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

أنا أميل إلى استخدام Autoresetevent. للحالات مثل هذه:

private AutoResetEvent _waitHandle = new AutoResetEvent(false);

private void OpenForm()
{
    Thread formThread = new Thread(FormStub);
    formThread.SetApartmentState(ApartmentState.STA);
    formThread.Start();
    _waitHandle.WaitOne();

    // when you come here FormStub has signaled                
}

private void FormStub()
{
    // do the work

    // signal that we are done
    _waitHandle.Set();
}

هناك طريقة أخرى لتمرير EventWAithandle هي تمريرها إلى FormStub كمعلمة (لذلك لا تضعف طراز كائنك):

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    EventWaitHandle e = new EventWaitHandle(false, EventResetMode.ManualReset);
    Thread t = new Thread(FormStub);
    t.SetApartmentState(ApartmentState.STA);
    t.Start(e);
    e.WaitOne();
}

static void FormStub(object param)
{
    EventWaitHandle e = (EventWaitHandle) param;
    Form f = new Form1();

    e.Set();
    Application.Run(new Form1());
}

استخدم BOOL ثابتا لمعرفة ما إذا كان قد تم تحميل النموذج أم لا. انها ذرية لذلك لن تحتاج إلى قفل.

في الكود الرئيسي فقط تفعل شيئا مثل

while(!formRun) { Thread.Sleep(100); }

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

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