Last active
September 2, 2017 12:48
-
-
Save urasandesu/449574c8581c64c5ffa0134a3bfcff73 to your computer and use it in GitHub Desktop.
Compositable Synchronization Primitives
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace Synq | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("*** Wait until ending 'Process' in order of all tasks ***"); | |
{ | |
var waiter1 = Synchronizable.EventWait(obj => (int)obj == 1); | |
var waiter2 = Synchronizable.EventWait(obj => (int)obj == 2); | |
var waiter3 = Synchronizable.EventWait(obj => (int)obj == 3); | |
using (var sync = waiter1.Then(waiter2).Then(waiter3).GetSynchronizer()) | |
{ | |
var task1 = Task.Run(() => | |
{ | |
Console.WriteLine("Start 1 ..."); | |
Thread.Sleep(1000); | |
sync.Begin(1).Wait(); | |
Console.WriteLine("Process 1."); | |
sync.End(1).Wait(); | |
Console.WriteLine("End 1."); | |
}); | |
var task2 = Task.Run(() => | |
{ | |
Console.WriteLine("Start 2 ..."); | |
Thread.Sleep(2000); | |
sync.Begin(2).Wait(); | |
Console.WriteLine("Process 2."); | |
sync.End(2).Wait(); | |
Console.WriteLine("End 2."); | |
}); | |
var task3 = Task.Run(() => | |
{ | |
Console.WriteLine("Start 3 ..."); | |
sync.Begin(3).Wait(); | |
Console.WriteLine("Process 3."); | |
sync.End(3).Wait(); | |
Console.WriteLine("End 3."); | |
}); | |
sync.NotifyAll(false).Wait(); | |
Console.WriteLine("Ended 'Process' in order of all tasks."); | |
Task.WaitAll(task1, task2, task3); | |
Console.WriteLine(); | |
} | |
} | |
Console.WriteLine("*** Wait until beginning 'Start' of all tasks (the order is unrelated, also it doesn't concern whether 'Process' has processed) ***"); | |
{ | |
var setter1 = Synchronizable.EventSet(obj => (int)obj == 1); | |
var setter2 = Synchronizable.EventSet(obj => (int)obj == 2); | |
using (var sync = setter1.And(setter2).GetSynchronizer()) | |
{ | |
var task1 = Task.Run(() => | |
{ | |
Thread.Sleep(1000); | |
Console.WriteLine("Start 1 ..."); | |
sync.Begin(1).Wait(); | |
Thread.Sleep(1000); | |
Console.WriteLine("Process 1."); | |
sync.End(1).Wait(); | |
Console.WriteLine("End 1."); | |
}); | |
var task2 = Task.Run(() => | |
{ | |
Console.WriteLine("Start 2 ..."); | |
sync.Begin(2).Wait(); | |
Console.WriteLine("Process 2."); | |
sync.End(2).Wait(); | |
Console.WriteLine("End 2."); | |
}); | |
sync.NotifyAll(false).Wait(); | |
Console.WriteLine("Begun 'Start' of all tasks."); | |
Task.WaitAll(task1, task2); | |
Console.WriteLine(); | |
} | |
} | |
Console.WriteLine("*** Wait until beginning 'Start' of task1 or task2 and until ending 'Process' of task3 and task4 in order ***"); | |
{ | |
var setter1 = Synchronizable.EventSet(obj => (int)obj == 1, (sender, e) => Console.WriteLine($"Begun setter1"), (sender, e) => Console.WriteLine($"Ended setter1"), (sender, e) => Console.WriteLine($"AllNotified setter1")); | |
var setter2 = Synchronizable.EventSet(obj => (int)obj == 2, (sender, e) => Console.WriteLine($"Begun setter2"), (sender, e) => Console.WriteLine($"Ended setter2"), (sender, e) => Console.WriteLine($"AllNotified setter2")); | |
var waiter3 = Synchronizable.EventWait(obj => (int)obj == 3, (sender, e) => Console.WriteLine($"Begun waiter3"), (sender, e) => Console.WriteLine($"Ended waiter3"), (sender, e) => Console.WriteLine($"AllNotified waiter3")); | |
var waiter4 = Synchronizable.EventWait(obj => (int)obj == 4, (sender, e) => Console.WriteLine($"Begun waiter4"), (sender, e) => Console.WriteLine($"Ended waiter4"), (sender, e) => Console.WriteLine($"AllNotified waiter4")); | |
using (var sync = setter1.Or(setter2).And(waiter3.Then(waiter4)).GetSynchronizer()) | |
{ | |
var task1 = Task.Run(() => | |
{ | |
Thread.Sleep(3000); | |
Console.WriteLine("Start 1 ..."); | |
sync.Begin(1).Wait(); | |
Console.WriteLine("Process 1."); | |
sync.End(1).Wait(); | |
Console.WriteLine("End 1."); | |
}); | |
var task2 = Task.Run(() => | |
{ | |
Console.WriteLine("Start 2 ..."); | |
sync.Begin(2).Wait(); | |
Console.WriteLine("Process 2."); | |
sync.End(2).Wait(); | |
Console.WriteLine("End 2."); | |
}); | |
var task3 = Task.Run(() => | |
{ | |
Thread.Sleep(500); | |
Console.WriteLine("Start 3 ..."); | |
sync.Begin(3).Wait(); | |
Console.WriteLine("Process 3."); | |
sync.End(3).Wait(); | |
Console.WriteLine("End 3."); | |
}); | |
var task4 = Task.Run(() => | |
{ | |
Console.WriteLine("Start 4 ..."); | |
sync.Begin(4).Wait(); | |
Thread.Sleep(500); | |
Console.WriteLine("Process 4."); | |
sync.End(4).Wait(); | |
Console.WriteLine("End 4."); | |
}); | |
sync.NotifyAll(false).Wait(); | |
Console.WriteLine("Begun 'Start' of task1 or task2 and ended 'Process' of task3 and task4 in order."); | |
Task.WaitAll(task1, task2, task3, task4); | |
Console.WriteLine(); | |
} | |
} | |
Console.WriteLine("Press any key to continue..."); | |
Console.ReadLine(); | |
// Result --- | |
// | |
// *** Wait until ending 'Process' in order of all tasks *** | |
// Start 1 ... | |
// Start 2 ... | |
// Start 3 ... | |
// Process 1. | |
// End 1. | |
// Process 2. | |
// End 2. | |
// Process 3. | |
// End 3. | |
// Ended 'Process' in order of all tasks. | |
// | |
// *** Wait until beginning 'Start' of all tasks (the order is unrelated, also it doesn't concern whether 'Process' has processed) *** | |
// Start 2 ... | |
// Process 2. | |
// End 2. | |
// Start 1 ... | |
// Begun 'Start' of all tasks. | |
// Process 1. | |
// End 1. | |
// | |
// *** Wait until beginning 'Start' of task1 or task2 and until ending 'Process' of task3 and task4 in order *** | |
// Start 2 ... | |
// Start 4 ... | |
// AllNotified setter1 | |
// AllNotified setter2 | |
// Start 3 ... | |
// AllNotified waiter3 | |
// Process 3. | |
// Begun waiter4 | |
// Ended setter1 | |
// Ended setter2 | |
// Ended waiter4 | |
// End 3. | |
// Process 2. | |
// Ended setter1 | |
// Ended setter2 | |
// End 2. | |
// Begun setter2 | |
// Start 1 ... | |
// Process 4. | |
// Ended setter1 | |
// Ended setter2 | |
// Begun setter1 | |
// Ended waiter3 | |
// AllNotified waiter4 | |
// Begun 'Start' of task1 or task2 and ended 'Process' of task3 and task4 in order. | |
// End 4. | |
// Process 1. | |
// Ended setter1 | |
// Ended setter2 | |
// End 1. | |
// | |
// Press any key to continue... | |
} | |
} | |
public interface ISynchronizable | |
{ | |
ISynchronizer GetSynchronizer(); | |
} | |
[Serializable] | |
class InternalSynchronousOptions | |
{ | |
public InternalSynchronousOptions WithHandlingCondition(bool ignores = true) | |
{ | |
IgnoresHandlingCondition = ignores; | |
return this; | |
} | |
public bool IgnoresHandlingCondition { get; private set; } | |
} | |
[Serializable] | |
public class SynchronousOptions | |
{ | |
internal static SynchronousOptions UpdateInternalOptions(SynchronousOptions opts, InternalSynchronousOptions internalOpts) | |
{ | |
if (opts == null) | |
opts = new SynchronousOptions(); | |
opts.InternalOptions = internalOpts; | |
return opts; | |
} | |
internal InternalSynchronousOptions InternalOptions { get; private set; } | |
} | |
[Serializable] | |
public class HandledEventArgs : EventArgs | |
{ | |
public new static readonly HandledEventArgs Empty = new HandledEventArgs(); | |
public HandledEventArgs() : | |
this(null, null) | |
{ } | |
public HandledEventArgs(object obj, SynchronousOptions opts = null) | |
{ | |
Object = obj; | |
Options = opts; | |
} | |
public object Object { get; private set; } | |
public SynchronousOptions Options { get; private set; } | |
} | |
[Serializable] | |
public class AllNotifiedEventArgs : EventArgs | |
{ | |
public new static readonly AllNotifiedEventArgs Empty = new AllNotifiedEventArgs(); | |
public AllNotifiedEventArgs() : | |
this(false) | |
{ } | |
public AllNotifiedEventArgs(bool state) | |
{ | |
State = state; | |
} | |
public bool State { get; private set; } | |
} | |
public interface ISynchronizer : IDisposable | |
{ | |
bool WillHandle(object obj); | |
Task Begin(object obj, SynchronousOptions opts = null); | |
event EventHandler<HandledEventArgs> Begun; | |
Task End(object obj, SynchronousOptions opts = null); | |
event EventHandler<HandledEventArgs> Ended; | |
Task NotifyAll(bool state); | |
event EventHandler<AllNotifiedEventArgs> AllNotified; | |
} | |
abstract class EventSynchronizable : ISynchronizable | |
{ | |
readonly Predicate<object> m_willHandle; | |
readonly EventHandler<HandledEventArgs> m_handleBegun; | |
readonly EventHandler<HandledEventArgs> m_handleEnded; | |
readonly EventHandler<AllNotifiedEventArgs> m_handleAllNotified; | |
public EventSynchronizable(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) | |
{ | |
Debug.Assert(willHandle != null, $"Value cannot be null. Parameter name: { nameof(willHandle) }"); | |
m_willHandle = willHandle; | |
m_handleBegun = handleBegun; | |
m_handleEnded = handleEnded; | |
m_handleAllNotified = handleAllNotified; | |
} | |
public ISynchronizer GetSynchronizer() | |
{ | |
return GetEventSynchronizer(m_willHandle, m_handleBegun, m_handleEnded, m_handleAllNotified); | |
} | |
protected abstract EventSynchronizer GetEventSynchronizer(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null); | |
} | |
class EventWaitable : EventSynchronizable | |
{ | |
public EventWaitable(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) : | |
base(willHandle, handleBegun, handleEnded, handleAllNotified) | |
{ } | |
protected override EventSynchronizer GetEventSynchronizer(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) | |
{ | |
return new EventWaiter(willHandle, handleBegun, handleEnded, handleAllNotified); | |
} | |
} | |
class EventSettable : EventSynchronizable | |
{ | |
public EventSettable(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) : | |
base(willHandle, handleBegun, handleEnded, handleAllNotified) | |
{ } | |
protected override EventSynchronizer GetEventSynchronizer(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) | |
{ | |
return new EventSetter(willHandle, handleBegun, handleEnded, handleAllNotified); | |
} | |
} | |
abstract class EventSynchronizer : ISynchronizer | |
{ | |
readonly Predicate<object> m_willHandle; | |
readonly EventHandler<HandledEventArgs> m_handleBegun; | |
readonly EventHandler<HandledEventArgs> m_handleEnded; | |
readonly EventHandler<AllNotifiedEventArgs> m_handleAllNotified; | |
protected EventSynchronizer(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) | |
{ | |
Debug.Assert(willHandle != null, $"Value cannot be null. Parameter name: { nameof(willHandle) }"); | |
m_willHandle = willHandle; | |
m_handleBegun = handleBegun; | |
if (m_handleBegun != null) | |
Begun += m_handleBegun; | |
m_handleEnded = handleEnded; | |
if (m_handleEnded != null) | |
Ended += m_handleEnded; | |
m_handleAllNotified = handleAllNotified; | |
if (m_handleAllNotified != null) | |
AllNotified += m_handleAllNotified; | |
} | |
protected ManualResetEventSlim WaitHandle { get; private set; } = new ManualResetEventSlim(false); | |
public bool WillHandle(object obj) | |
{ | |
return m_willHandle(obj); | |
} | |
public abstract Task Begin(object obj, SynchronousOptions opts = null); | |
public event EventHandler<HandledEventArgs> Begun; | |
protected virtual void OnBegun(HandledEventArgs e) | |
{ | |
Begun?.Invoke(this, e); | |
} | |
public abstract Task End(object obj, SynchronousOptions opts = null); | |
public event EventHandler<HandledEventArgs> Ended; | |
protected virtual void OnEnded(HandledEventArgs e) | |
{ | |
Ended?.Invoke(this, e); | |
} | |
public Task NotifyAll(bool state) | |
{ | |
if (state) | |
{ | |
return Task.Run(() => | |
{ | |
AllNotified?.Invoke(this, new AllNotifiedEventArgs(state)); | |
WaitHandle.Set(); | |
}); | |
} | |
else | |
{ | |
return Task.Run(() => | |
{ | |
AllNotified?.Invoke(this, new AllNotifiedEventArgs(state)); | |
WaitHandle.Wait(); | |
}); | |
} | |
} | |
public event EventHandler<AllNotifiedEventArgs> AllNotified; | |
bool m_disposed; | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (!m_disposed) | |
{ | |
if (disposing) | |
{ | |
WaitHandle.Dispose(); | |
if (m_handleBegun != null) | |
Begun -= m_handleBegun; | |
if (m_handleEnded != null) | |
Ended -= m_handleEnded; | |
if (m_handleAllNotified != null) | |
AllNotified -= m_handleAllNotified; | |
} | |
m_disposed = true; | |
} | |
} | |
public void Dispose() | |
{ | |
Dispose(true); | |
} | |
} | |
class EventWaiter : EventSynchronizer | |
{ | |
public EventWaiter(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) : | |
base(willHandle, handleBegun, handleEnded, handleAllNotified) | |
{ } | |
public override Task Begin(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.Run(() => | |
{ | |
if (opts?.InternalOptions?.IgnoresHandlingCondition == true || WillHandle(obj)) | |
{ | |
OnBegun(new HandledEventArgs(obj, opts)); | |
WaitHandle.Wait(); | |
} | |
}); | |
} | |
public override Task End(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.Run(() => | |
{ | |
if (opts?.InternalOptions?.IgnoresHandlingCondition == true || WillHandle(obj)) | |
{ | |
OnEnded(new HandledEventArgs(obj, opts)); | |
WaitHandle.Set(); | |
} | |
}); | |
} | |
} | |
class EventSetter : EventSynchronizer | |
{ | |
public EventSetter(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) : | |
base(willHandle, handleBegun, handleEnded, handleAllNotified) | |
{ } | |
public override Task Begin(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.Run(() => | |
{ | |
if (opts?.InternalOptions?.IgnoresHandlingCondition == true || WillHandle(obj)) | |
{ | |
OnBegun(new HandledEventArgs(obj, opts)); | |
WaitHandle.Set(); | |
} | |
}); | |
} | |
public override Task End(object obj, SynchronousOptions opts = null) | |
{ | |
OnEnded(new HandledEventArgs(obj, opts)); | |
return Task.CompletedTask; | |
} | |
} | |
abstract class BinarySynchronizable : ISynchronizable | |
{ | |
readonly ISynchronizable m_lhs; | |
readonly ISynchronizable m_rhs; | |
protected BinarySynchronizable(ISynchronizable lhs, ISynchronizable rhs) | |
{ | |
Debug.Assert(lhs != null, $"Value cannot be null. Parameter name: { nameof(lhs) }"); | |
Debug.Assert(rhs != null, $"Value cannot be null. Parameter name: { nameof(rhs) }"); | |
m_lhs = lhs; | |
m_rhs = rhs; | |
} | |
public ISynchronizer GetSynchronizer() | |
{ | |
return GetBinarySynchronizer(m_lhs.GetSynchronizer(), m_rhs.GetSynchronizer()); | |
} | |
protected abstract BinarySynchronizer GetBinarySynchronizer(ISynchronizer lhs, ISynchronizer rhs); | |
} | |
class ThenSynchronizable : BinarySynchronizable | |
{ | |
public ThenSynchronizable(ISynchronizable lhs, ISynchronizable rhs) : | |
base(lhs, rhs) | |
{ } | |
protected override BinarySynchronizer GetBinarySynchronizer(ISynchronizer lhs, ISynchronizer rhs) | |
{ | |
return new ThenSynchronizer(lhs, rhs); | |
} | |
} | |
class AndSynchronizable : BinarySynchronizable | |
{ | |
public AndSynchronizable(ISynchronizable lhs, ISynchronizable rhs) : | |
base(lhs, rhs) | |
{ } | |
protected override BinarySynchronizer GetBinarySynchronizer(ISynchronizer lhs, ISynchronizer rhs) | |
{ | |
return new AndSynchronizer(lhs, rhs); | |
} | |
} | |
class OrSynchronizable : BinarySynchronizable | |
{ | |
public OrSynchronizable(ISynchronizable lhs, ISynchronizable rhs) : | |
base(lhs, rhs) | |
{ } | |
protected override BinarySynchronizer GetBinarySynchronizer(ISynchronizer lhs, ISynchronizer rhs) | |
{ | |
return new OrSynchronizer(lhs, rhs); | |
} | |
} | |
abstract class BinarySynchronizer : ISynchronizer | |
{ | |
protected BinarySynchronizer(ISynchronizer lhs, ISynchronizer rhs) | |
{ | |
Debug.Assert(lhs != null, $"Value cannot be null. Parameter name: { nameof(lhs) }"); | |
Debug.Assert(rhs != null, $"Value cannot be null. Parameter name: { nameof(rhs) }"); | |
LeftSynchronizer = lhs; | |
RightSynchronizer = rhs; | |
} | |
protected ISynchronizer LeftSynchronizer { get; private set; } | |
protected ISynchronizer RightSynchronizer { get; private set; } | |
public abstract bool WillHandle(object obj); | |
public abstract Task Begin(object obj, SynchronousOptions opts = null); | |
public event EventHandler<HandledEventArgs> Begun | |
{ | |
add | |
{ | |
if (LeftSynchronizer != null) | |
LeftSynchronizer.Begun += value; | |
if (RightSynchronizer != null) | |
RightSynchronizer.Begun += value; | |
} | |
remove | |
{ | |
if (LeftSynchronizer != null) | |
LeftSynchronizer.Begun -= value; | |
if (RightSynchronizer != null) | |
RightSynchronizer.Begun -= value; | |
} | |
} | |
public abstract Task End(object obj, SynchronousOptions opts = null); | |
public event EventHandler<HandledEventArgs> Ended | |
{ | |
add | |
{ | |
if (LeftSynchronizer != null) | |
LeftSynchronizer.Ended += value; | |
if (RightSynchronizer != null) | |
RightSynchronizer.Ended += value; | |
} | |
remove | |
{ | |
if (LeftSynchronizer != null) | |
LeftSynchronizer.Ended -= value; | |
if (RightSynchronizer != null) | |
RightSynchronizer.Ended -= value; | |
} | |
} | |
public abstract Task NotifyAll(bool state); | |
public event EventHandler<AllNotifiedEventArgs> AllNotified | |
{ | |
add | |
{ | |
if (LeftSynchronizer != null) | |
LeftSynchronizer.AllNotified += value; | |
if (RightSynchronizer != null) | |
RightSynchronizer.AllNotified += value; | |
} | |
remove | |
{ | |
if (LeftSynchronizer != null) | |
LeftSynchronizer.AllNotified -= value; | |
if (RightSynchronizer != null) | |
RightSynchronizer.AllNotified -= value; | |
} | |
} | |
bool m_disposed; | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (!m_disposed) | |
{ | |
if (disposing) | |
{ | |
LeftSynchronizer.Dispose(); | |
RightSynchronizer.Dispose(); | |
} | |
m_disposed = true; | |
} | |
} | |
public void Dispose() | |
{ | |
Dispose(true); | |
} | |
} | |
class ThenSynchronizer : BinarySynchronizer | |
{ | |
public ThenSynchronizer(ISynchronizer lhs, ISynchronizer rhs) : | |
base(lhs, rhs) | |
{ } | |
public override bool WillHandle(object obj) | |
{ | |
return RightSynchronizer.WillHandle(obj); | |
} | |
public override async Task Begin(object obj, SynchronousOptions opts = null) | |
{ | |
if (LeftSynchronizer.WillHandle(obj) && LeftSynchronizer is BinarySynchronizer) | |
await LeftSynchronizer.Begin(obj, opts); | |
else | |
await RightSynchronizer.Begin(obj, opts); | |
} | |
public override async Task End(object obj, SynchronousOptions opts = null) | |
{ | |
var willLeftHandle = LeftSynchronizer.WillHandle(obj); | |
var willRightHandle = RightSynchronizer.WillHandle(obj); | |
if (willLeftHandle && willRightHandle) | |
await Task.CompletedTask; | |
else if (willLeftHandle) | |
await RightSynchronizer.End(obj, SynchronousOptions.UpdateInternalOptions(opts, new InternalSynchronousOptions().WithHandlingCondition())); | |
else if (willRightHandle) | |
await LeftSynchronizer.End(obj, SynchronousOptions.UpdateInternalOptions(opts, new InternalSynchronousOptions().WithHandlingCondition())); | |
else | |
await LeftSynchronizer.End(obj, opts); | |
} | |
public override async Task NotifyAll(bool state) | |
{ | |
await LeftSynchronizer.NotifyAll(state); | |
await RightSynchronizer.NotifyAll(state); | |
} | |
} | |
class AndSynchronizer : BinarySynchronizer | |
{ | |
public AndSynchronizer(ISynchronizer lhs, ISynchronizer rhs) : | |
base(lhs, rhs) | |
{ } | |
public override bool WillHandle(object obj) | |
{ | |
return true; | |
} | |
public override Task Begin(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.WhenAll(LeftSynchronizer.Begin(obj, opts), RightSynchronizer.Begin(obj, opts)); | |
} | |
public override Task End(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.WhenAll(LeftSynchronizer.End(obj, opts), RightSynchronizer.End(obj, opts)); | |
} | |
public override Task NotifyAll(bool state) | |
{ | |
return Task.WhenAll(LeftSynchronizer.NotifyAll(state), RightSynchronizer.NotifyAll(state)); | |
} | |
} | |
class OrSynchronizer : BinarySynchronizer | |
{ | |
public OrSynchronizer(ISynchronizer lhs, ISynchronizer rhs) : | |
base(lhs, rhs) | |
{ } | |
public override bool WillHandle(object obj) | |
{ | |
return true; | |
} | |
public override Task Begin(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.WhenAny(LeftSynchronizer.Begin(obj, opts), RightSynchronizer.Begin(obj, opts)); | |
} | |
public override Task End(object obj, SynchronousOptions opts = null) | |
{ | |
return Task.WhenAny(LeftSynchronizer.End(obj, opts), RightSynchronizer.End(obj, opts)); | |
} | |
public override Task NotifyAll(bool state) | |
{ | |
return Task.WhenAny(LeftSynchronizer.NotifyAll(state), RightSynchronizer.NotifyAll(state)); | |
} | |
} | |
public static class Synchronizable | |
{ | |
public static ISynchronizable EventWait(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) | |
{ | |
if (willHandle == null) | |
throw new ArgumentNullException(nameof(willHandle)); | |
return new EventWaitable(willHandle, handleBegun, handleEnded, handleAllNotified); | |
} | |
public static ISynchronizable EventSet(Predicate<object> willHandle, | |
EventHandler<HandledEventArgs> handleBegun = null, EventHandler<HandledEventArgs> handleEnded = null, EventHandler<AllNotifiedEventArgs> handleAllNotified = null) | |
{ | |
if (willHandle == null) | |
throw new ArgumentNullException(nameof(willHandle)); | |
return new EventSettable(willHandle, handleBegun, handleEnded, handleAllNotified); | |
} | |
public static ISynchronizable Then(this ISynchronizable lhs, ISynchronizable rhs) | |
{ | |
if (lhs == null) | |
throw new ArgumentNullException(nameof(lhs)); | |
if (rhs == null) | |
throw new ArgumentNullException(nameof(rhs)); | |
return new ThenSynchronizable(lhs, rhs); | |
} | |
public static ISynchronizable And(this ISynchronizable lhs, ISynchronizable rhs) | |
{ | |
if (lhs == null) | |
throw new ArgumentNullException(nameof(lhs)); | |
if (rhs == null) | |
throw new ArgumentNullException(nameof(rhs)); | |
return new AndSynchronizable(lhs, rhs); | |
} | |
public static ISynchronizable Or(this ISynchronizable lhs, ISynchronizable rhs) | |
{ | |
if (lhs == null) | |
throw new ArgumentNullException(nameof(lhs)); | |
if (rhs == null) | |
throw new ArgumentNullException(nameof(rhs)); | |
return new OrSynchronizable(lhs, rhs); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
面白そうだったので書いてみました。Awaiter実装しようとしたんですが、Taskのほうが汎用性ありそうだったのでそっちで。
https://gist.github.com/kekyo/3f1e58766bd6f1273d725509f54f0fd3