У меня проблема с загрузкой и фильтрацией потоков данных.Пожалуйста, помогите мне сделать этот код безопасным.
Следующий код базового класса моего элемента управления, который обрабатывает всю совокупность данных через BackgroundWorker. Это приводит к ошибке «this.DataWorker.RunWorkerAsync()», говорящей, что BackgroundWorker занят.
/// <summary>
/// Handles the population of the form data.
/// </summary>
/// <param name="reload">Whether to pull data back from the WebService.</param>
public void Populate(bool reload)
{
if (!this.DataWorker.IsBusy)
{
// Disable the filter options
IvdSession.Instance.FilterManager.SetEnabledState(this.GetType(), false);
// Perform the population
this.DataWorker.RunWorkerAsync(reload);
}
else if (!reload)
{
// If the data worker is busy and this is a not reload, then something bad has happened (i.e. the filter has run during a reload.)
throw new InvalidOperationException("The DataWorker was busy whilst asked to reload.");
}
}
код называется в два возможных мест. Во-первых, с помощью таймера на форме, что управление находится на:
private void tmrAutoRefresh_Tick(object sender, EventArgs e)
{
if (!(this.CurrentBody == null))
{
this.CurrentBody.Populate(true);
}
}
А во-вторых, каждый раз, когда пользователь выбирает фильтр вариант из ряда выпадающих списков:
public void Filter()
{
if (!m_BlockFilter)
{
IvdInstance.Main.CurrentBody.FirstRun = true;
IvdInstance.Main.CurrentBody.Populate(false);
}
}
таймера на основная форма запускается каждые 60 секунд и переходит к методу Population. Передача перезарядки в истинах говорит BackgroundWorker, что нужно снести новый набор данных из WebService:
void dataWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (base.FirstRun)
{
base.CleanListView();
}
if ((bool)e.Argument)
{
byte[] serialized = IvdSession.DataAccess.GetServiceCalls(IvdSession.Instance.Company.Description, IvdSession.Instance.Company.Password, null);
m_DataCollection = new DalCollection<ServiceCallEntity>(serialized);
}
List<ServiceCallEntity> collection = this.ApplyFilter();
base.HandlePopulation<ServiceCallEntity>(collection, e);
}
catch (WebException ex)
{
// Ignore - Thrown when user clicks cancel
}
catch (System.Web.Services.Protocols.SoapException ex)
{
// Log error on server and stay transparent to user
base.LogError(ex);
}
catch (System.Data.SqlClient.SqlException ex)
{
// Inform user that the database is unavailable
base.HandleSystemUnavailable(ex);
}
}
Насколько мне известно, эта ошибка возникает, когда мне удается щелкнуть параметр фильтра в точности в то же время таймер запускает событие популяции. Я полагаю, что что-то отсутствует в методе Populate, то есть в блокировке, но я не уверен, как правильно его использовать в этом случае.
Код относится к пользовательскому вводу. Если пользователь выбирает параметр фильтра, автоматическое обновление должно быть заблокировано, если происходит автоматическое обновление, параметры фильтра временно отключены. Если они срабатывают одновременно, пользовательский ввод должен иметь приоритет (если это возможно).
Надеюсь, кто-то может помочь!
@Groo, не знаете точную спецификацию Windows, но с несколькими ядрами, не могли бы вы одновременно запустить две вещи? –
Да, метод * должен * быть потокобезопасным. Но есть правило, что вы всегда должны обновлять элементы Gui из потока Gui. Поэтому Windows.Forms.Timer позаботится о добавлении обработчика событий в очередь потоков Gui (он вызывает его из потока Gui), чтобы упростить ситуацию. – Groo
Эй, кто ты шутишь с «Не знаю точной спецификации Windows»? :) – Groo