2012-03-01 15 views
1

実行時にいくつかのスクリプトを実行していますが、UIがフリーズしています。スレッド内でCodeProviderを呼び出していますが、まだフリーズしています。私のフォームでAPPをフリーズせずにそのスレッドからスレッドを待つ方法はありますか?

は、私が呼び出す:私は自分のコードを実行し続けるために、スレッドの仕上がりを待ちたいので、私はmre.WaitOne()を使用してい

var mre = new ManualResetEvent(false); 
Thread tr = new Thread(() => 
    { 
     Script sp = new Script(); 
     code = textBox.Text; 
     sp.Comp(code); 
     mre.Set(); 
    }); 
tr.Start(); 
mre.WaitOne(); 

もCompileメソッドの内部で同じ方法を使用しようとしました:

public bool Comps(string code) 
{ 
    var mre = new ManualResetEvent(false); 
    Thread tr = new Thread(() => 
    { 
     //Code to generate a CompilerResult and generate the assembly 
     Run(); 
     mre.Set(); 
    }); 
    tr.Start(); 
    mre.WaitOne(); 
    return true; 
} 

しかし、それは待っている間、それはまだUIを凍結します。

アイデア?

おかげ

+0

アプリがWPFベースの場合、[this](http://msdn.microsoft.com/en-us/magazine/cc163328.aspx)に関連する必要があります。 – sovanesyan

+1

あなたの 'mre.Set();'はスレッドの最後です。つまり、 'mre.WaitOne();'は 'tr.Join();'と同じです。つまり、全体が本質的にシングルスレッドです。 –

答えて

4

私は自分のコードを実行し続けるために、スレッド仕上げ を待ちたいので、私はmre.WaitOne()を使用しています。

処理スレッドが処理を完了するまで、呼び出しスレッドを強制的にフリーズさせると、どのようなことが起こりますか?このようにすると、その余分なスレッドを持つことに意味はなく、呼び出し元のスレッドがUIスレッドであれば、もちろんフリーズします。

バックグラウンド処理を行う場合、結果を同期して待つことはできません。代わりに、処理が完了したことをUIに通知する必要があります。つまり、コールバックを使用するか、形。

+0

+1 - GUIイベントハンドラで待っています:(( –

2

マルチスレッドの重要なポイントは、スレッドを他のスレッドとは独立して実行できるようにすることです。あなたがしたいことは、コールバックを使ってスレッドの完了を知らせることです。その後、UIがその完了に応答するようにします。

BackgroundWorkerクラスには、この目的ですでにイベントが組み込まれています。

あなたが購読したい3つのイベントがあります。あなたの仕事はどうなる場所

bw.DoWork += 
    new DoWorkEventHandler(bw_DoWork); 
bw.ProgressChanged += 
    new ProgressChangedEventHandler(bw_ProgressChanged); 
bw.RunWorkerCompleted += 
    new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 

DoWorkです。 ProgressChangedでは、進行状況のUIを更新できます。 は、DoWork機能が完了したときにイベントをポップします。

このオブジェクトはスレッドを処理し、bw.RunWorkerAsync()呼び出しを実行することによって非同期に実行するように設定できます。

このため、詳細については、以下のページを参照してください。例として

http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx

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

    private void Form1_Load(object sender, EventArgs e) 
    { 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     MessageBox.Show(String.Format("UI thread: {0}", Thread.CurrentThread.ManagedThreadId)); 
     this.Invoke(new MethodInvoker(delegate() { MessageBox.Show(String.Format("Invoke thread: {0}", Thread.CurrentThread.ManagedThreadId)); })); 

     backgroundWorker1.RunWorkerAsync(); 
    } 

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     MessageBox.Show(String.Format("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId)); 
    } 
} 

この例では、フォームにボタン一つ一つのバックグラウンドワーカーを追加することによって構築することができます。 button1_ClickおよびbackgroundWorker1_DoWork関数のイベントデザイナーを介してイベントを配線します。 button1をクリックした後にポップアップする3つのMessagesBoxが必要です。UIスレッドとInvokeスレッドのIdが同じであることに気付くでしょう。つまり、呼び出しから何らかの処理を行うと、UIスレッドが待機することになります。 3番目のポップアップは、別のIDを持つワーカースレッドからのものです。

+0

ありがとう、私はちょうどそれを使って作業する方法を見つけました、それは今のところうまくいきます) – Kyore

+0

私はバックグラウンドワークを使用しようとしました。私の問題ですが、私はそれがクロススレッドの例外を返しているのを見て、私が使用する場合: this.Invoke(新しいMethodInvoker(デリゲート){sp.Comp(コード);})); それはUIをフリーズする – Kyore

+0

あなたの処理がメインのUIスレッドで起こっているようですが、回答の最後に例を追加して振る舞いを示しています。 – Walk

1

完了したらBeginInvokeを使用してください。例:

delegate void MyAction(); 

void Form1_Load(object sender, EventArgs e) 
{ 
    Thread tr = new Thread(() => 
    { 
     Script sp = new Script(); 
     code = textBox.Text; 
     sp.Comp(code); 

     BeginInvoke(new MyAction(ThreadOperationEnded)); 
    }); 
    tr.Start(); 
} 

void ThreadOperationEnded() 
{ 
    MessageBox.Show("Finished!"); 
} 
関連する問題