如何在不冻结我的APP的情况下等待线程退出该线程?

时间:2012-03-01 21:52:52

标签: c# multithreading

我在运行时运行了一些脚本,但它冻结了我的UI,我在一个Thread中调用CodeProvider,但它仍然冻结。

在我的表格中,我打电话:

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

我正在使用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;
}

但正在等待它仍然冻结用户界面。

有什么想法吗?

由于

3 个答案:

答案 0 :(得分:4)

  

我正在使用mre.WaitOne(),因为我想等待线程完成   继续运行我的代码。

如果强制调用线程冻结直到处理线程完成处理,您会发生什么?这样做,没有必要拥有额外的线程,如果调用线程是UI线程,当然它会冻结。

如果你进行后台处理,你不能同步等待结果,而是你必须以某种方式通知UI处理完成,即使用回调或以其他形式将结果发送回UI

答案 1 :(得分:2)

多线程的全部意义在于允许Thread独立于任何其他线程执行。您要做的是使用回调来表示您的线程完成,然后让您的UI响应完成。

BackgroundWorker类已经为此目的内置了一个事件。

您要订阅三个活动:

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

DoWork是您工作的地方。 ProgressChanged允许您更新进度的UI。 RunWorkerCompleted将在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后,您应该弹出三个MessagesBox。您会注意到UI线程的Id和Invoke线程是相同的,这意味着您从调用执行的任何处理都将导致UI线程等待。第三个弹出窗口来自工作线程,它具有不同的ID。

答案 2 :(得分: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!" );
}