throw new AggregateException (exceptions);
}
+ /* This is the callback registered on linked tokens
+ * so that they don't throw an ODE if the callback
+ * is called concurrently with a Dispose
+ */
+ void SafeLinkedCancel ()
+ {
+ try {
+ Cancel ();
+ } catch (ObjectDisposedException) {}
+ }
+
#if NET_4_5
public void CancelAfter (TimeSpan delay)
{
throw new ArgumentException ("Empty tokens array");
CancellationTokenSource src = new CancellationTokenSource ();
- Action action = src.Cancel;
+ Action action = src.SafeLinkedCancel;
var registrations = new List<CancellationTokenRegistration> (tokens.Length);
foreach (CancellationToken token in tokens) {
using System.Threading;
using NUnit.Framework;
using System.Threading.Tasks;
+using MonoTests.System.Threading.Tasks;
namespace MonoTests.System.Threading
{
Assert.IsTrue (canceled, "#3");
}
+
+ [Test]
+ public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
+ {
+ ParallelTestHelper.Repeat (delegate {
+ var src = new CancellationTokenSource ();
+ var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
+ var cntd = new CountdownEvent (2);
+
+ var t1 = new Thread (() => {
+ if (!cntd.Signal ())
+ cntd.Wait ();
+ src.Cancel ();
+ });
+ var t2 = new Thread (() => {
+ if (!cntd.Signal ())
+ cntd.Wait ();
+ linked.Dispose ();
+ });
+
+ t1.Start ();
+ t2.Start ();
+ t1.Join (500);
+ t2.Join (500);
+ }, 500);
+ }
}
}