我在运行时运行了一些脚本,但它冻结了我的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;
}
但正在等待它仍然冻结用户界面。
有什么想法吗?
由于
答案 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!" );
}