Windows Develop Bookmark and Share   
 index > Windows Forms General > potential race condition in a delegate
 

potential race condition in a delegate

I have a Visual Studio 2008 C# .Net 3.5 SP1 project with a custom defined UserControl. The control definesa delegate that is executed when an internal state is changed. Does this method shown in the code block below involve a potential race condition? If so, what is the correct pattern to use?

public partial class MyListView : UserControl
{
    private void OnCheckStateChanged(object sender, EventArgs e)
    {
        // ...
        
        OnItemEnabledChanged(new MyItemEnabledChangedEventArgs());
    }
    
    protected virtual void OnItemEnabledChanged(MyItemEnabledChangedEventArgs e)
    {
        // is this a potential race condition?
        if (ItemEnabledChanged != null)
            ItemEnabledChanged(this, e);
    }
    
    public delegate void MyItemEnabledChangedEventHandler(object sender, MyItemEnabledChangedEventArgs e);
    
    public class MyItemEnabledChangedEventArgs : EventArgs
    {
        public MyItemEnabledChangedEventArgs()
        {
        }
    }
}


Thanks,
PaulH
PaulH79  Wednesday, September 09, 2009 9:36 PM
Hi,

Yes, there is a possible race condition here;

if (ItemEnabledChanged != null)
ItemEnabledChanged(this, e);

A thread switch can occur between the 'if' and the ItemEnabledChanged call, and that can lead to a null reference exception if during that thread switch all event handlers are disconnected. You can sort of solve it by doing this;

MyItemEnabledChangedEventHandler eventDelegate = ItemEnabledChanged;
if (eventDelegate != null)
eventDelegate(this, e);

Multi-cast delegates (used by events) are immtuable, so getting a reference to the the delegate and then using that rather than the shared variable guarantees you won't get the null exception because the invocation list can't change for the reference you first got. However, this isn't perfect either.... there is no absolutely safe way of raising an event and getting predictable behaviour in a multi-threaded scenario in C#, at least not without putting additional logic in each event handler as well.

To see the possible problems that can still occur using the above pattern, see Eric Lippert's excellent blog article here;

http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx


  • Marked As Answer byPaulH79 Thursday, September 10, 2009 1:54 PM
  • Proposed As Answer byRudedog2 Thursday, September 10, 2009 1:13 AM
  •  
Yort  Thursday, September 10, 2009 12:10 AM
Hi,

Yes, there is a possible race condition here;

if (ItemEnabledChanged != null)
ItemEnabledChanged(this, e);

A thread switch can occur between the 'if' and the ItemEnabledChanged call, and that can lead to a null reference exception if during that thread switch all event handlers are disconnected. You can sort of solve it by doing this;

MyItemEnabledChangedEventHandler eventDelegate = ItemEnabledChanged;
if (eventDelegate != null)
eventDelegate(this, e);

Multi-cast delegates (used by events) are immtuable, so getting a reference to the the delegate and then using that rather than the shared variable guarantees you won't get the null exception because the invocation list can't change for the reference you first got. However, this isn't perfect either.... there is no absolutely safe way of raising an event and getting predictable behaviour in a multi-threaded scenario in C#, at least not without putting additional logic in each event handler as well.

To see the possible problems that can still occur using the above pattern, see Eric Lippert's excellent blog article here;

http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx


  • Marked As Answer byPaulH79 Thursday, September 10, 2009 1:54 PM
  • Proposed As Answer byRudedog2 Thursday, September 10, 2009 1:13 AM
  •  
Yort  Thursday, September 10, 2009 12:10 AM
Great answer. Thanks for the link to the blog post.

-PaulH
PaulH79  Thursday, September 10, 2009 1:55 PM
No problem, glad to have helped !
Yort  Thursday, September 10, 2009 9:22 PM

You can use google to search for other answers

Custom Search

More Threads

• How to generate automatic last modified date and updated by when a record changes or a record is added
• Minimizing to tray... have it working but have a problem
• Attempted to read or write protected memory. This is often an indication that other memory is corrupt
• Print Gridview
• Creating a windows service
• How to get current system settings about [Animate controls and elements insode windows] in Vista?
• CAB Custom ModuleInit Not Firing
• PDF viewing. simple question. .NET 2.0
• Embed an Image into another Image
• Please help with "Not a member of" error