質問

ネットの奇数ロックセマンティクスが再び私を盗聴されています。

私はスレッドを起動するよ、ターン内の子スレッドはフォームを開始します。フォームが作成されるまで、親スレッドが待機しなければならない。

私の最初の試みは、フォーム変数を監視するモニタを使用していました

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であるため、失敗します。

私は非常に簡単にダミーの整数または何かを(私は実際に私はFormThread変数をcanabalizeと思う)作成することもできますが、よりエレガントな解決策があった場合、私は思っていた。

役に立ちましたか?

解決

この場合のためのより良い同期プリミティブます:

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());
}

フォームがロードされたか否かをフラグに静的ブール値を使用します。 それは原子であるので、ロックは必要ありません。

メインのコードでは、単に

のような何かを
while(!formRun) { Thread.Sleep(100); }

本当の問題は、なぜあなたはこれをやっているのですか? 通常は、メインスレッドがヘルパーのコードを実行するためのGUIのもの、および二次スレッドを実行したいです。 あなたがそれを必要とする理由を説明している場合、私たちはより良い技術と多分思い付くことができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top