【发布时间】:2011-07-01 15:23:25
【问题描述】:
我有一个永远不会返回的线程调用调用。
线程一直运行良好,直到我以这种方式调用该行,“owner.Invoke(methInvoker);”
调试的时候,我可以慢慢地一步,一步,一步,但是一旦我点击owner.Invoke...就结束了!
Control owner;
public event ReportCeProgressDelegate ProgressChanged;
public void ReportProgress(int step, object data) {
if ((owner != null) && (ProgressChanged != null)) {
if (!CancellationPending) {
ThreadEventArg e = new ThreadEventArg(step, data);
if (owner.InvokeRequired) {
MethodInvoker methInvoker = delegate { ProgressChanged(this, e); };
owner.Invoke(methInvoker);
} else {
ProgressChanged(this, e);
}
} else {
mreReporter.Set();
mreReporter.Close();
}
}
}
仅供参考:这是一个模仿 BackgroundWorker 类的自定义类,它在没有表单的控件上不可用。
认为Invoke可能不需要,我在调试器中手动将光标移到那部分代码上并尝试直接调用ProgressChanged,但是VS2010的调试器抛出了跨线程异常。
编辑:
由于我收到了前 3 个 cmets,我想用我的 ProgressChanged 方法更新:
worker.ProgressChanged += delegate(object sender, ThreadEventArg e) {
if (progressBar1.Style != ProgressBarStyle.Continuous) {
progressBar1.Value = 0;
object data = e.Data;
if (data != null) {
progressBar1.Maximum = 100;
}
progressBar1.Style = ProgressBarStyle.Continuous;
}
progressBar1.Value = e.ProgressPercentage;
};
匿名方法的第一行有一个断点,但它也永远不会被命中。
编辑 2
这里是线程调用的更完整列表:
List<TableData> tList = CollectTablesFromForm();
if (0 < tList.Count) {
using (SqlCeReporter worker = new SqlCeReporter(this)) {
for (int i = 0; i < tList.Count; i++) {
ManualResetEvent mre = new ManualResetEvent(false);
worker.StartThread += SqlCeClass.SaveSqlCeDataTable;
worker.ProgressChanged += delegate(object sender, ThreadEventArg e) {
if (progressBar1.Style != ProgressBarStyle.Continuous) {
progressBar1.Value = 0;
object data = e.Data;
if (data != null) {
progressBar1.Maximum = 100;
}
progressBar1.Style = ProgressBarStyle.Continuous;
}
progressBar1.Value = e.ProgressPercentage;
};
worker.ThreadCompleted += delegate(object sender, ThreadResultArg e) {
Cursor = Cursors.Default;
progressBar1.Visible = false;
progressBar1.Style = ProgressBarStyle.Blocks;
if (e.Error == null) {
if (e.Cancelled) {
MessageBox.Show(this, "Save Action was Cancelled.", "Save Table " + tList[i].TableName);
}
} else {
MessageBox.Show(this, e.Error.Message, "Error Saving Table " + tList[i].TableName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
mre.Set();
};
worker.RunWorkerAsync(tList[i]);
progressBar1.Value = 0;
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = true;
Cursor = Cursors.WaitCursor;
mre.WaitOne();
}
}
}
我希望这不是矫枉过正!我讨厌提供太多信息,因为那样我会让人们批评我的风格。 :)
【问题讨论】:
-
被调用的方法是完全不同的过程,在方法的开头添加断点,这样你就可以进入它了。
-
事件循环可以绑定到其他地方。我会检查另一个处理程序中是否有任何阻塞。
-
你有没有在调试器挂起时暂停它,进入“线程”调试窗口,双击每个线程,查看它的调用堆栈和执行位置并寻找 1) 死锁 (例如,代码在多个地方的“Wait”或“WaitAll”处暂停)2)一般奇怪的操作。记下应用程序冻结前 GUI 线程的线程 ID,尤其是在冻结后查看它在做什么。
标签: c# multithreading backgroundworker invoke