Search code examples
c#multithreadingwinformsbackgroundworker

Dead lock with backgroundWorker


I faced with one interesting moment when working with multithreading. I have two threads. In main thread I create layout and add to it control,in second thread I create another control and add to the same layout. It works fine, but second thread works a bit longer then main. So main should wait for second thread.I use for this AutoResetEvent and got DeadLock. Below I describe code what I use:

 private static AutoResetEvent resetEvent = new AutoResetEvent(false);
    private BackgroundWorker backgroundAdvancedViewWorker = new BackgroundWorker();
    private delegate void ShowViewDelegate();

    public void Run()
    {
        MainGeneralReportForm mainForm = ObjectFactory.GetOrCreateView<IMainGeneralReportForm>();
        backgroundSimpleViewWorker.RunWorkerAsync(_mainForm);
        GeneralReportFormatView formatView =
                        ObjectFactory.ShowView<IGeneralReportFormatView>()
        resetEvent.WaitOne();
        DoSomething(advancedSearchView);
    }

    private void backgroundAdvancedViewWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        MainGeneralReportForm mainForm = e.Argument as MainGeneralReportForm;

        if (mainForm!= null && mainForm.InvokeRequired)
        {
            mainForm.BeginInvoke(new ShowViewDelegate(() =>
            {
              advancedSearchView =
                    ObjectFactory.ShowView<IGeneralReportAdvancedSearchView>();                  
              resetEvent.Set();
             }));
            }
        }
    }

If main thread doesn't wait for second thread, the application throws NullReferenceException. Is exist any solution or workaround of this problem?


Solution

  • You block main thread by resetEvent.WaitOne(); and at the same time trying to schedule work item back to main thread with BeginInvoke (which indeed can't run as main thread is waiting).

    Not sure what right fix would be, but blocking on main thread is not really an option.

    Maybe some "state" field on the form may be enough. Or maybe running DoSomething(advancedSearchView); from BeginInvoke callback (instead of resetEvent.Set();).

    Note: if you are on 4.5 you can consider using async/await instead of manual threading.