2

希望你一切都好。

我遇到了 BeginInvoke 的一个奇怪问题,我真的很需要你的帮助!

我有一个类 Reporting ,其中包含多个 Reporting 类型的实例

Class Reporting : UserControl
{
  //Reports are inherited from UserControl
  Report _report1;
  Report _report2;
  Report _report3;

  //Instanciate and return the Report corresponding to the passed ID (The report is 
  //instanciated and created only if it's null)   
  public Report GetReport(int reportId);

  public delegate void GenerateReportAsImageDelegate(int reportId,string path)

  //Generate the report and save it as image
  public void GenerateReportAsImage(int reportId,string path)
  {
    if(InvokeRequired)
    {
      BeginInvoke(new GenerateReportAsImageDelegate(GenerateReportAsImage),new      object[]{reportId,path});

    }
    else
    {
      //... Generating the report etc..
    }
 }

  ....
}

它是一个显示在表单中的用户控件,同样的用户控件也用于 Windows 服务,以每分钟生成报告(并保存为图像)。

为了每分钟生成一份报告,我使用了 System.Threading.Timer。

这是我的班级在服务中生成报告的样子:

class ReportServiceClass
{

  Reporting _reportingObject;
  System.Threading.Timer _timer;

  Public ReportingServiceClass(int reportId)
  {
     _timer = new Timer(new TimerCallback(this.CreateReport), reportId, 0, 1000) 
  }

  private void CreateReport(Object stateInfo)
  {  
     int reportId = Convert.ToInt32(stateInfo);

    //To ensure that the _reportingObject is created on the same thread as the report
    if(_reportingObject == null)
      _reportingObject = new _reportingObject();

    _reportingObject.GenerateReportAsImage(reportId,@"c:\reports\report.PNG")
  }

}

几乎一切都运行良好.. 除了有时 CreateReport 是在 ThreadPool 的另一个线程中执行的。因此,当我对报告及其组件(已在另一个线程中创建)执行一些操作时,InvokeRequired 设置为 true,这非常明显......但是 BeginInvoke 不执行任何操作!这几乎就像创建报告的线程不再存在......

你们对如何避免这个问题有任何想法吗?

我已经面临这个问题一个星期了,我已经用谷歌搜索和 stackoverflowed 。但什么都没有!

非常感谢 !

4

2 回答 2

1

我认为你使用了错误的调用,试试这个:

if(this.InvokeRequired)
{
   this.Invoke(new Action<int,string>(GenerateReportAsImage), reportId, path);    
}
else
  ...
于 2010-01-22T18:18:03.303 回答
0

以下来自 ThreadPool.SetMinThreads 文档:

空闲线程由线程池维护,以减少满足线程池线程请求所需的时间。为工作线程和异步 I/O 线程维护单独的最小值。超过最小值的空闲线程被终止,以节省系统资源。空闲线程的维护是一项后台任务。

另外,我的理解是 BeginInvoke 和 Invoke 依赖于 WinForms“消息泵”来实际调用您的代码。我从未听说过它们被用在服务中——似乎该机制是为具有可见 UI 和消息泵的真正 WinForms 应用程序设计的。让它在服务中可靠地工作是可能的 - 但似乎您至少应该创建自己的线程,而不是使用 ThreadPool 来创建 UserControl 并管理调用的线程。

您可能想要也可能不想使用 Invoke 而不是 BeginInvoke。前者是同步的,后者是异步的。

于 2010-01-22T18:44:26.337 回答