Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:方法调用从不返回_C#_Multithreading_Backgroundworker_Invoke - Fatal编程技术网

C#:方法调用从不返回

C#:方法调用从不返回,c#,multithreading,backgroundworker,invoke,C#,Multithreading,Backgroundworker,Invoke,我有一个线程调用,永远不会返回 线程一直正常运行,直到我这样调用行,“owner.Invoke(methInvoker);” 调试时,我可以慢慢地一步一步地进行,但一旦我点击了owner.Invoke。。。结束了 Control owner; public event ReportCeProgressDelegate ProgressChanged; public void ReportProgress(int step, object data) { if ((owner != null

我有一个线程调用,永远不会返回

线程一直正常运行,直到我这样调用行,“
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
类,该类在没有表单的控件上不可用

考虑到可能不需要调用,我手动将调试器中的光标移到该部分代码上,并尝试直接调用
ProgressChanged
,但VS2010的调试器抛出了一个跨线程异常

编辑:

由于我收到的前3条评论,我想用我的
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();
    }
  }
}
List tList=CollectTablesFromForm();
如果(0<列表计数){
使用(SqlCeReporter worker=newsqlcereporter(this)){
for(int i=0;i

我希望这不是太过分了!我讨厌提供太多的信息,因为这样我会让人们批评我的风格

用户界面和工作线程可能已死锁<代码>控制。调用
通过将消息发布到UI线程的消息队列,将委托的执行封送到UI线程,然后等待该消息被处理,这反过来意味着委托的执行必须在
控制之前完成。调用
返回。但是,如果您的UI线程除了发送和处理消息外,还忙于做其他事情,该怎么办?我可以从您的代码中看出,这里可能有一个
ManualResetEvent
。在调用
WaitOne
时,您的UI线程是否碰巧被阻塞?如果是这样,那肯定是个问题。由于
WaitOne
不传输消息,因此它将阻止UI线程,这将导致从工作线程调用
Control.Invoke
时出现死锁

如果希望
ProgressChanged
事件的行为与
BackgroundWorker
类似,则需要调用
控件。调用
将这些事件处理程序放到UI线程上。这就是
BackgroundWorker
的工作方式。当然,您不必在这方面完全模仿
BackgroundWorker
类,只要您准备好让调用方在处理
ProgressChanged
事件时自己进行封送处理

  worker.RunWorkerAsync(tList[i]);
  //...
  mre.WaitOne();
这肯定是一个僵局。传递给Control.Begin/Invoke()的委托只能在UI线程空闲并重新进入消息循环时运行。您的UI线程不是空闲的,它在WaitOne()调用中被阻塞。在工作线程完成之前,该调用无法完成。在完成Invoke()调用之前,工作线程无法完成。在UI线程空闲之前,该调用无法完成。死锁之城


阻塞UI线程从根本上来说是错误的。不仅仅是因为.NET管道,COM已经要求它永不阻塞。这就是为什么BGW有一个RunWorkerCompleted事件。

调用的Methodos是一个完全不同的过程,在方法的开头添加断点,这样u就可以进入它。事件循环可能会被绑定到其他地方。我会检查另一个处理程序中是否有任何阻塞。您是否在调试器挂起时暂停调试器,转到“线程”调试窗口,双击每个线程,查看其调用堆栈和执行位置,并查找死锁(例如,代码在多个位置暂停在“等待”或“等待所有”)2)一般操作。在应用程序冻结之前,请注意GUI线程的线程ID,并特别查看它在冻结之后执行的操作。第一个代码块中引用的
ManualResetEvent
仅局限于自定义线程类…到目前为止,我还没有真正使用它。如果我需要的话,这似乎是取消一个非常漫长的过程的好方法。另一方面,主线程(UI)也有自己的
ManualResetEvent
。代码块的任务是在表单上保存一个或多个数据表,我希望防止多个表同时保存到本地SQL CE数据库。见编辑2的代码(张贴不久)。这也是布赖恩的评论让我思考的。看起来我需要重新设计类的各个部分。好吧,删除mre.WaitOne()调用即可。然后开始思考