Skip to content

Instantly share code, notes, and snippets.

@alpinskiy
Created January 20, 2015 20:42
Show Gist options
  • Save alpinskiy/ef1f4705c70e4dde1443 to your computer and use it in GitHub Desktop.
Save alpinskiy/ef1f4705c70e4dde1443 to your computer and use it in GitHub Desktop.
Exception & thread safe event
using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
namespace CustomEvent
{
public sealed class Program
{
public event EventHandler CustomEvent
{
add
{
EventHandler current = _eventHandler, start;
do
{
start = current;
var desired = (EventHandler) Delegate.Combine(current, value);
current = Interlocked.CompareExchange(ref _eventHandler, desired, start);
}
while (start != current);
}
remove
{
EventHandler current = _eventHandler, start;
do
{
start = current;
var desired = (EventHandler) Delegate.Remove(current, value);
current = Interlocked.CompareExchange(ref _eventHandler, desired, start);
}
while (start != current);
}
}
public /*protected*/ void RaiseCustomEvent(EventArgs e)
{
var handler = Volatile.Read(ref _eventHandler);
if (handler == null)
{
return;
}
foreach (var h in handler.GetInvocationList().Cast<EventHandler>())
{
try
{
h(this, e);
}
catch (Exception)
{
// TODO: trace
}
}
}
private EventHandler _eventHandler;
}
[TestFixture]
public class ProgramTest
{
[Test]
public void Perform()
{
var p = new Program();
const int NumberOfSubscribers = 10000;
Task.WaitAll(Enumerable
.Range(0, NumberOfSubscribers)
.Select(_ => Task.Factory.StartNew(() =>
{
p.CustomEvent += OnCustomEvent;
}))
.ToArray());
p.RaiseCustomEvent(EventArgs.Empty);
Assert.That(_counter, Is.EqualTo(NumberOfSubscribers));
_counter = 0;
Task.WaitAll(Enumerable
.Range(0, NumberOfSubscribers)
.Select(_ => Task.Factory.StartNew(() =>
{
p.CustomEvent -= OnCustomEvent;
}))
.ToArray());
p.RaiseCustomEvent(EventArgs.Empty);
Assert.That(_counter, Is.EqualTo(0));
_counter = 0;
}
private void OnCustomEvent(object o, EventArgs e)
{
Interlocked.Increment(ref _counter);
}
private int _counter;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment