2

我有一个后台工作者,它从数据库中收集大量数据。我想在线程上设置一个超时限制,以便如果它在设定的时间后没有返回结果,则取消该过程。

我在启动 BackgroundWorker 的同时在主线程上启动了一个计时器。

如果我故意让 BGW 进入睡眠状态,计时器就会过去并调用 .Elapsed 事件。然后它取消后台工作人员,但是它没有成功完成我希望它完成的其他操作,即更新 GUI 上的状态栏并抛出 MessageBox。我不明白为什么不,有人可以帮忙吗?

超时和睡眠是专门为测试设置的。

        /// <summary>
        /// loads Assets by group ID
        /// Populates Grid on asset listing page
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="user"></param>
        internal void PopulateGridAssetsByGroup(int groupId, User user)
        {
            //update statusbar
            AfMainWindow.MainWindow.UpdateStatusBar("Loading Assets...");

            //setup BG worker
            populateGridAssetsWorker = new BackgroundWorker {WorkerSupportsCancellation = true, WorkerReportsProgress = false};
            populateGridAssetsWorker.DoWork += populateGridAssetsWorker_DoWork;
            populateGridAssetsWorker.RunWorkerCompleted += populateGridAssetsWorker_RunWorkerCompleted;

            //setup timer which will cancel the background worker if it runs too long
            cancelTimer = new Timer {Interval = 2000, Enabled = true, AutoReset = false};
            cancelTimer.Elapsed += cancelTimer_Elapsed;
            cancelTimer.Start();

            populateGridAssetsWorker.RunWorkerAsync(groupId); //start bg worker
        }


        void cancelTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            populateGridAssetsWorker.CancelAsync();
            cancelTimer.Stop();

            AfMainWindow.MainWindow.UpdateStatusBar("Could not load assets, timeout error");

            MessageBox.Show("Operation Timed Out\n\nThe Server did not respond quick enough, please try again",
                            "Timeout", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK);

            AfMainWindow.MainWindow.Busy.IsBusy = false;

        }

        /// <summary>
        /// when bg worker complete, update the AssetGrid on Asset Listing Page with results
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void populateGridAssetsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            cancelTimer.Stop();

            //my thread complete processing

        }        
        /// <summary>
        /// Perform the DB query and collect results for asset listing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void populateGridAssetsWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var assetListByGroup = new List<AssetLinked>();

            Thread.Sleep(5000);

            if (populateGridAssetsWorker.CancellationPending)
            {
                return;
            }

            try
            {

              //My SQL actions 

            if (populateGridAssetsWorker.CancellationPending)
            {
                return;
            }
            }
            catch (Exception ex)
            {
                Globals.AFWideSettings.GeneralErrorMessage(ex.Message);
            }
        }
4

1 回答 1

2

想当cancelTimer_Elapsed您尝试从另一个线程更新 GUI 时,您的方法会静默崩溃。后台线程中抛出的异常有时很难在不调试的情况下找到,Visual Studio 设置为在所有异常上中断 - 您可以在菜单中设置它Debug > Exceptions并检查所有 CLR 异常。或者,您可以将方法体包装在一个try块中,并将断点放在 catch 块中。

void cancelTimer_Elapsed(object sender, ElapsedEventArgs e)
{
   try
   {
        populateGridAssetsWorker.CancelAsync();
        cancelTimer.Stop();

        AfMainWindow.MainWindow.UpdateStatusBar("Could not load assets, timeout error");

        MessageBox.Show("Operation Timed Out\n\nThe Server did not respond quick enough, please try again",
                        "Timeout", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK);

        AfMainWindow.MainWindow.Busy.IsBusy = false;
    }
    catch(Exception ex)
    {
        int breakpoint = 42;
    }
}

我不确定是否是这种情况,但我认为值得一试。

于 2013-01-24T22:46:49.343 回答