Pato
Pato

Reputation: 161

Problem with BeginInvoke (the delegate does not perfom any action)

hope you're well.

I'm facing a curious problem with BeginInvoke and I really really need your help !

I have a class Reporting which contains multiple instances of type Report

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..
    }
 }

  ....
}

It's a user control shown in a form and this same usercontrol is also used from a Windows Service to generate reports (and saved as image) every minutes.

To generate a report every minute, i'm using the System.Threading.Timer.

Here is what my class generating the reports looks like in the service :

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")
  }

}

Almost everything is working well .. excepet that sometimes CreateReport is executed in an other thread of the ThreadPool. So when i'm performing some actions on the report and its components (which have been created in an other thread), the InvokeRequired is set to true and it's totaly obvious... But the BeginInvoke does not perform any action ! It's almost like the thread where the report have been created no longer exist ...

You guys have any ideas on how to avoid this problem ?

It's been now a week that i'm facing this problem, i haved googled and stackoverflowed . but nothing !

Thanks a lot !

Upvotes: 2

Views: 2133

Answers (2)

Henk Holterman
Henk Holterman

Reputation: 273691

I think you use the wrong Invoke, try this:

if(this.InvokeRequired)
{
   this.Invoke(new Action<int,string>(GenerateReportAsImage), reportId, path);    
}
else
  ...

Upvotes: 1

Joe Erickson
Joe Erickson

Reputation: 7227

The following is from the ThreadPool.SetMinThreads documentation:

Idle threads are maintained by the thread pool in order to reduce the time required to satisfy requests for thread pool threads. Separate minimums are maintained for worker threads and asynchronous I/O threads. Idle threads in excess of the minimums are terminated, to save system resources. Maintenance of the idle threads is a background task.

Also, my understanding is that BeginInvoke and Invoke rely on the WinForms "message pump" for the actual invocation of your code. I have never heard of them being used in a service - it seems like the mechanism is designed for a real WinForms application with a visible UI and a message pump. Getting it to work reliably in a service may be possible - but it seems like you should at least create your own thread rather than using the ThreadPool for the thread which creates the UserControl and manages the invocations.

You may or may not want to use Invoke rather than BeginInvoke. The former is synchronous and the latter is asynchronous.

Upvotes: 0

Related Questions