2

This problem puzzled me for a while, I think I understand the issue now, but I cant figure out the implementation detail to fix it.

I have a background thread running that has a function that repeatedly gets a datagridview cell contents by calling code via Invoke(). The problem occurs when the user clicks on the form close. I get an "Object disposed exception" when trying to access the datagridview on that form. That makes sense, so I added a line to not call Invoke if the control already has been disposed. This solution doesnt work however. What must be happening is that I have a race condition where I check the disposed flag is false, but at that exact point the main gui thread runs and closes the form and disposes the DGV.

public delegate object dlgMethod(Control ctrl, string methodName, object param1, object param2, object param3, object param4);

    public object method(Control ctrl, string methodName, object param1 = null, object param2 = null, object param3 = null, object param4 = null)
    {
        object retVal = null;

        if (ctrl.InvokeRequired)
        {
            if (!ctrl.IsDisposed)
               retVal = ctrl.Invoke(new dlgMethod(method), new object[] { ctrl, methodName, param1, param2, param3, param4 });

            return retVal;
        }
        else
        {  // code snipped

I am guessing there are 2 ways to fix this ?

1) I could try and make the ctrl.isDisposed test and the Invoke atomic, there is maybe a way to do this with a lambda call, but I cant figure out the syntax ?

or 2) Use EventWaitHandler class to improve the thread synchronizing so that the exception cant happen ?

Would greatly appreciate any example how to fix up the broken code above please ?

Regards Geoff

geoffw123
  • 83
  • 5
  • 1
    Place the call to `ctrl.IsDisposed` inside the delegate, so that it too runs on the UI thread. – Lasse V. Karlsen Nov 03 '16 at 11:05
  • You've got no less than **four** threading race bugs in this snippet. The nastiest one is the one you haven't found yet and the one you will *not* get an exception for to tell you that your code is wrong. The Invoke() call is quite evil and completely unsynchronized with the UI. Fails miserably when the user modifies the DGV cell content while or after you called Invoke(). Whatever result you compute will be wrong and mismatch the DGV content. Fixable by disabling the DGV but now it no longer makes sense to use Invoke() at all, you can get the value before you start the thread. – Hans Passant Nov 03 '16 at 12:02
  • http://stackoverflow.com/a/1732361/17034 – Hans Passant Nov 03 '16 at 12:03
  • Hi Lasse, thanks for the reply. That didnt help me though, I had kinda already figured out I need to make it atomic or shift the isDisposed test into the gui thread. My problem is how do I do that ? I find C# delegates and Invoke syntax confusing. Could you post actual rejigged code example please ? Thanks again – geoffw123 Nov 03 '16 at 12:03
  • H Lasse thanks for the reply. For info, The DGV is not user editable, it is just upated every 0.5 Secs. Just counting the number of threading bugs in the code sample without posting improved or fixed sample code doesnt really help me though, or I suspect anyone else reading this in future. – geoffw123 Nov 03 '16 at 12:13
  • Instead of creating and managing thread, why don't you use `BackgroundWorker` https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx, which automatically takes care of such issues. – Akash Kava Nov 03 '16 at 12:36

0 Answers0