Проблема с BeginInvoke (делегат не выполняет никаких действий) - PullRequest
2 голосов
/ 22 января 2010

надеюсь, ты в порядке.

У меня возникла любопытная проблема с BeginInvoke, и мне действительно нужна ваша помощь!

У меня есть класс Reporting, который содержит несколько экземпляров типа 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..
    }
 }

  ....
}

Это пользовательский элемент управления, отображаемый в форме, и этот же пользовательский элемент управления также используется службой 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 не выполняет никаких действий! Это похоже на то, что поток, в котором был создан отчет, больше не существует ...

У вас, ребята, есть идеи, как избежать этой проблемы?

Прошла неделя, когда я столкнулся с этой проблемой, я погуглил и переполнился стеком. но ничего!

Большое спасибо!

Ответы [ 2 ]

1 голос
/ 22 января 2010

Я думаю, что вы используете неправильный Invoke, попробуйте это:

if(this.InvokeRequired)
{
   this.Invoke(new Action<int,string>(GenerateReportAsImage), reportId, path);    
}
else
  ...
0 голосов
/ 22 января 2010

Следующее из документации ThreadPool.SetMinThreads:

Свободные потоки поддерживаются пулом потоков, чтобы сократить время, необходимое для удовлетворения запросов на потоки пула потоков. Отдельные минимумы поддерживаются для рабочих потоков и потоков асинхронного ввода-вывода. Свободные потоки сверх минимальных значений прекращаются для экономии системных ресурсов. Поддержание свободных потоков является фоновой задачей.

Кроме того, я понимаю, что BeginInvoke и Invoke полагаются на «насос сообщений» WinForms для фактического вызова вашего кода. Я никогда не слышал о том, чтобы они использовались в сервисе - похоже, механизм предназначен для реального приложения WinForms с видимым пользовательским интерфейсом и насосом сообщений. Надежно заставить его работать в службе - но кажется, что вы должны по крайней мере создать свой собственный поток вместо использования ThreadPool для потока, который создает UserControl и управляет вызовами.

Вы можете или не хотите использовать Invoke, а не BeginInvoke. Первый является синхронным, а второй - асинхронным.

...