From bb5436d7e86dac449f3d2834854f4a5c68550027 Mon Sep 17 00:00:00 2001 From: Dingping Zhang Date: Tue, 16 Nov 2021 13:04:22 +0800 Subject: [PATCH] bugfix: ensure that execution events are synchronized. (#12) --- HandyIpc.Generator/ClientProxy.cs | 5 ++++- HandyIpc.Tests/EventTypeTest.cs | 12 ++++++++---- HandyIpc/Core/AwaiterManager.cs | 15 +++++++++++---- HandyIpc/Core/NotifierManager.cs | 2 -- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/HandyIpc.Generator/ClientProxy.cs b/HandyIpc.Generator/ClientProxy.cs index 8b84ce9..a28eb3e 100644 --- a/HandyIpc.Generator/ClientProxy.cs +++ b/HandyIpc.Generator/ClientProxy.cs @@ -32,7 +32,9 @@ public class {nameof(ClientProxy)}{className}{typeParameters} : {interfaceType} private readonly string _key; private readonly AwaiterManager _awaiterManager; -{events.For(item => $@"private event {item.Type.ToTypeDeclaration()} _{item.Name};")} +{events.For(item => $@" + private event {item.Type.ToTypeDeclaration()} _{item.Name}; +")} {events.For(item => { @@ -63,6 +65,7 @@ public class {nameof(ClientProxy)}{className}{typeParameters} : {interfaceType} }} }} }} + "; })} diff --git a/HandyIpc.Tests/EventTypeTest.cs b/HandyIpc.Tests/EventTypeTest.cs index 8aa8e56..597eb3c 100644 --- a/HandyIpc.Tests/EventTypeTest.cs +++ b/HandyIpc.Tests/EventTypeTest.cs @@ -33,8 +33,12 @@ public void TestEventHandlerWithNamedPipe() TestEventHandlerSubscribeAndUnsubscribe(instance); } - private void TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) + private static void TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) { + // Some issues will occur only when the number of tests is high. + // In particular, it tests whether the event calls are synchronized. + const int testCount = 10000; + int count1 = 0; int count2 = 0; int count3 = 0; @@ -49,7 +53,7 @@ private void TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) instance.Changed += handler2; instance.Changed += handler3; - for (int i = 0; i < 10; i++) + for (int i = 0; i < testCount; i++) { instance.RaiseChanged(EventArgs.Empty); Assert.Equal(i + 1, count1); @@ -65,7 +69,7 @@ private void TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) instance.Changed -= handler2; instance.Changed -= handler3; - for (int i = 0; i < 10; i++) + for (int i = 0; i < testCount; i++) { instance.RaiseChanged(EventArgs.Empty); Assert.Equal(0, count1); @@ -79,7 +83,7 @@ private void TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) instance.Changed += handler2; instance.Changed += handler3; - for (int i = 0; i < 10; i++) + for (int i = 0; i < testCount; i++) { instance.RaiseChanged(EventArgs.Empty); Assert.Equal(2 * (i + 1), count1); diff --git a/HandyIpc/Core/AwaiterManager.cs b/HandyIpc/Core/AwaiterManager.cs index 85c6519..72567c3 100644 --- a/HandyIpc/Core/AwaiterManager.cs +++ b/HandyIpc/Core/AwaiterManager.cs @@ -37,8 +37,7 @@ public void Unsubscribe(string name) { if (_pool.TryRemove(name, out _)) { - using var rented = _sender.ConnectionPool.Rent(); - byte[] removeResult = rented.Value.Invoke(Subscription.Remove(_key, name, _serializer)); + byte[] removeResult = _sender.Invoke(Subscription.Remove(_key, name, _serializer)); if (!removeResult.IsUnit()) { // TODO: Logging. @@ -58,8 +57,16 @@ private static void LoopWait(Awaiter awaiter) break; } - connection.Write(Signals.Unit); - awaiter.Handler(input); + try + { + // The Read() and Write() are used to ensure that calls are synchronized (blocked) + // and that the Write() must be called after the execution of the Handler() is completed. + awaiter.Handler(input); + } + finally + { + connection.Write(Signals.Unit); + } } } diff --git a/HandyIpc/Core/NotifierManager.cs b/HandyIpc/Core/NotifierManager.cs index 85e38ec..144b6c0 100644 --- a/HandyIpc/Core/NotifierManager.cs +++ b/HandyIpc/Core/NotifierManager.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace HandyIpc.Core @@ -6,7 +5,6 @@ namespace HandyIpc.Core public class NotifierManager { private readonly object _locker = new(); - private readonly string _key = Guid.NewGuid().ToString(); private readonly ISerializer _serializer; private readonly Dictionary _notifiers = new();