mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-11 19:44:55 +00:00
feat: Adding IcdAutoResetEvent and IcdMaunalResetEvent
This commit is contained in:
committed by
Chris Cameron
parent
c08a6283b8
commit
63d76d8cef
188
ICD.Common.Utils.Tests/IcdAutoResetEventTest.cs
Normal file
188
ICD.Common.Utils.Tests/IcdAutoResetEventTest.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
class IcdAutoResetEventTest
|
||||
{
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void InitialStateTest(bool initialState)
|
||||
{
|
||||
using (var waitHandleEvent = new IcdAutoResetEvent(initialState))
|
||||
{
|
||||
Assert.AreEqual(initialState, waitHandleEvent.WaitOne(1), "Initial state incorrect");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultInitialStateTest()
|
||||
{
|
||||
using (var waitHandleEvent = new IcdAutoResetEvent())
|
||||
{
|
||||
Assert.False(waitHandleEvent.WaitOne(1), "Initial state incorrect");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(5)]
|
||||
[TestCase(15)]
|
||||
public void MultipleThreadSetTest(int count)
|
||||
{
|
||||
int releasedCount = 0;
|
||||
|
||||
SafeCriticalSection countSection = new SafeCriticalSection();
|
||||
|
||||
|
||||
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
waitHandleEvent.WaitOne();
|
||||
countSection.Execute(() => releasedCount++);
|
||||
;
|
||||
});
|
||||
|
||||
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released early");
|
||||
|
||||
///Auto reset should only release one thread at a time
|
||||
for (int i = 1; i <= count; i++)
|
||||
{
|
||||
waitHandleEvent.Set();
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.AreEqual(i, countSection.Execute(() => releasedCount),
|
||||
"Incorrect number of threads released");
|
||||
}
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(5)]
|
||||
[TestCase(15)]
|
||||
public void MultipleThreadResetTest(int count)
|
||||
{
|
||||
int releasedCount = 0;
|
||||
|
||||
SafeCriticalSection countSection = new SafeCriticalSection();
|
||||
|
||||
|
||||
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(true);
|
||||
|
||||
Assert.True(waitHandleEvent.WaitOne(1), "Initial State Wrong");
|
||||
|
||||
waitHandleEvent.Reset();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
if (waitHandleEvent.WaitOne(100))
|
||||
countSection.Execute(() => releasedCount++);
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(2000);
|
||||
|
||||
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Incorrect number of threads released");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released after timeout");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(200)]
|
||||
[TestCase(5000)]
|
||||
public void WaitOneTest(int waitTime)
|
||||
{
|
||||
bool released = false;
|
||||
|
||||
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
|
||||
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
waitHandleEvent.WaitOne();
|
||||
released = true;
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(waitTime);
|
||||
|
||||
Assert.False(released, "Thread released when it shouldn't have");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.True(released, "Thread didn't release after set event");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(200)]
|
||||
[TestCase(500)]
|
||||
[TestCase(5000)]
|
||||
public void WaitOneTimeoutTest(int waitTime)
|
||||
{
|
||||
bool released = false;
|
||||
|
||||
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
|
||||
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
waitHandleEvent.WaitOne(waitTime * 2);
|
||||
released = true;
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(waitTime);
|
||||
|
||||
Assert.False(released, "Thread released when it shouldn't have");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.True(released, "Thread didn't release after set event");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(200)]
|
||||
[TestCase(500)]
|
||||
[TestCase(5000)]
|
||||
public void WaitOneTimedOutTest(int waitTime)
|
||||
{
|
||||
bool released = false;
|
||||
bool? returned = null;
|
||||
|
||||
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
|
||||
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
returned = waitHandleEvent.WaitOne(waitTime);
|
||||
released = true;
|
||||
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.True(returned == null, "WaitOne returned when it shouldn't have");
|
||||
Assert.False(released, "Thread released when it shouldn't have");
|
||||
|
||||
ThreadingUtils.Sleep(waitTime * 2);
|
||||
|
||||
Assert.True(released, "Thread didn't release after timeout");
|
||||
Assert.True(returned.HasValue && returned.Value == false, "WaitOne timeout didn't return false");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
183
ICD.Common.Utils.Tests/IcdManualResetEventTest.cs
Normal file
183
ICD.Common.Utils.Tests/IcdManualResetEventTest.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
class IcdManualResetEventTest
|
||||
{
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void InitialStateTest(bool initialState)
|
||||
{
|
||||
using (var waitHandleEvent = new IcdManualResetEvent(initialState))
|
||||
{
|
||||
Assert.AreEqual(initialState, waitHandleEvent.WaitOne(1), "Initial state incorrect");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultInitialStateTest()
|
||||
{
|
||||
using (var waitHandleEvent = new IcdManualResetEvent())
|
||||
{
|
||||
Assert.False(waitHandleEvent.WaitOne(1), "Initial state incorrect");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(5)]
|
||||
[TestCase(15)]
|
||||
public void MultipleThreadSetTest(int count)
|
||||
{
|
||||
int releasedCount = 0;
|
||||
|
||||
SafeCriticalSection countSection = new SafeCriticalSection();
|
||||
|
||||
|
||||
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
waitHandleEvent.WaitOne();
|
||||
countSection.Execute(() => releasedCount++);
|
||||
;
|
||||
});
|
||||
|
||||
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released early");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
ThreadingUtils.Sleep(500);
|
||||
|
||||
Assert.AreEqual(count, countSection.Execute(() => releasedCount), "Incorrect number of threads released");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(5)]
|
||||
[TestCase(15)]
|
||||
public void MultipleThreadResetTest(int count)
|
||||
{
|
||||
int releasedCount = 0;
|
||||
|
||||
SafeCriticalSection countSection = new SafeCriticalSection();
|
||||
|
||||
|
||||
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(true);
|
||||
|
||||
Assert.True(waitHandleEvent.WaitOne(1), "Initial State Wrong");
|
||||
|
||||
waitHandleEvent.Reset();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
if (waitHandleEvent.WaitOne(100))
|
||||
countSection.Execute(() => releasedCount++);
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(2000);
|
||||
|
||||
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Incorrect number of threads released");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released after timeout");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(200)]
|
||||
[TestCase(5000)]
|
||||
public void WaitOneTest(int waitTime)
|
||||
{
|
||||
bool released = false;
|
||||
|
||||
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
|
||||
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
waitHandleEvent.WaitOne();
|
||||
released = true;
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(waitTime);
|
||||
|
||||
Assert.False(released, "Thread released when it shouldn't have");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.True(released, "Thread didn't release after set event");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(200)]
|
||||
[TestCase(500)]
|
||||
[TestCase(5000)]
|
||||
public void WaitOneTimeoutTest(int waitTime)
|
||||
{
|
||||
bool released = false;
|
||||
|
||||
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
|
||||
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
waitHandleEvent.WaitOne(waitTime * 2);
|
||||
released = true;
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(waitTime);
|
||||
|
||||
Assert.False(released, "Thread released when it shouldn't have");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.True(released, "Thread didn't release after set event");
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
|
||||
[TestCase(200)]
|
||||
[TestCase(500)]
|
||||
[TestCase(5000)]
|
||||
public void WaitOneTimedOutTest(int waitTime)
|
||||
{
|
||||
bool released = false;
|
||||
bool? returned = null;
|
||||
|
||||
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
|
||||
|
||||
ThreadingUtils.SafeInvoke(() =>
|
||||
{
|
||||
returned = waitHandleEvent.WaitOne(waitTime);
|
||||
released = true;
|
||||
|
||||
});
|
||||
|
||||
ThreadingUtils.Sleep(100);
|
||||
|
||||
Assert.True(returned == null, "WaitOne returned when it shouldn't have");
|
||||
Assert.False(released, "Thread released when it shouldn't have");
|
||||
|
||||
ThreadingUtils.Sleep(waitTime * 2);
|
||||
|
||||
Assert.True(released, "Thread didn't release after timeout");
|
||||
Assert.True(returned.HasValue && returned.Value == false, "WaitOne timeout didn't return false");
|
||||
|
||||
waitHandleEvent.Set();
|
||||
|
||||
waitHandleEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
106
ICD.Common.Utils/AbstractIcdResetEvent.cs
Normal file
106
ICD.Common.Utils/AbstractIcdResetEvent.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
using System.Threading;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
public abstract class AbstractIcdResetEvent : IDisposable
|
||||
{
|
||||
|
||||
#if SIMPLSHARP
|
||||
private readonly CEvent m_Event;
|
||||
#else
|
||||
private readonly EventWaitHandle m_Event;
|
||||
#endif
|
||||
|
||||
#if SIMPLSHARP
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdManualResetEvent class with the CEvent
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
protected AbstractIcdResetEvent(CEvent eventHandle)
|
||||
{
|
||||
m_Event = eventHandle;
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdManualResetEvent class with the CEvent
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
protected AbstractIcdResetEvent(EventWaitHandle eventHandle)
|
||||
{
|
||||
m_Event = eventHandle;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
|
||||
/// </summary>
|
||||
/// <returns>true if the operation succeeds; otherwise, false.</returns>
|
||||
[PublicAPI]
|
||||
public bool Set()
|
||||
{
|
||||
return m_Event.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the state of the event to nonsignaled, causing threads to block.
|
||||
/// </summary>
|
||||
/// <returns>true if the operation succeeds; otherwise, false.</returns>
|
||||
[PublicAPI]
|
||||
public bool Reset()
|
||||
{
|
||||
return m_Event.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to wait for the event to be signaled. This will block indefinitely until the event is signaled.
|
||||
/// </summary>
|
||||
/// <returns>True if the current instance receives a signal otherwise false.</returns>
|
||||
[PublicAPI]
|
||||
public bool WaitOne()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
return m_Event.Wait();
|
||||
#else
|
||||
return m_Event.WaitOne();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to wait for the event to be signaled.
|
||||
/// </summary>
|
||||
/// <param name="timeout">Timeout in milliseconds or Timeout.Infinite to wait indefinitely.</param>
|
||||
/// <returns>True if the current instance receives a signal otherwise false.</returns>
|
||||
public bool WaitOne(int timeout)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
return m_Event.Wait(timeout);
|
||||
#else
|
||||
return m_Event.WaitOne(timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up of resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
m_Event.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the event to release all resources used by this instance.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void Close()
|
||||
{
|
||||
m_Event.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,6 +121,9 @@
|
||||
<Compile Include="Extensions\CollectionExtensions.cs" />
|
||||
<Compile Include="Extensions\RegistryExtensions.cs" />
|
||||
<Compile Include="Extensions\VersionExtensions.cs" />
|
||||
<Compile Include="AbstractIcdResetEvent.cs" />
|
||||
<Compile Include="IcdAutoResetEvent.cs" />
|
||||
<Compile Include="IcdManualResetEvent.cs" />
|
||||
<Compile Include="ThreadedWorkerQueue.cs" />
|
||||
<Compile Include="TimeZoneInfo\IcdTimeZoneInfo.cs" />
|
||||
<Compile Include="ObfuscationSettings.cs" />
|
||||
|
||||
39
ICD.Common.Utils/IcdAutoResetEvent.cs
Normal file
39
ICD.Common.Utils/IcdAutoResetEvent.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using ICD.Common.Properties;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
# else
|
||||
using System.Threading;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies one or more waiting threads that an event has occurred. Every thread that passes WaitOne causes the event to be reset
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class IcdAutoResetEvent : AbstractIcdResetEvent
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdAutoResetEvent class with the initial state to nonsignaled.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public IcdAutoResetEvent() : this(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdManualResetEvent class with a Boolean value indicating whether to set the initial state to signaled.
|
||||
/// </summary>
|
||||
/// <param name="initialState">true to set the initial state signaled; false to set the initial state to nonsignaled.</param>
|
||||
[PublicAPI]
|
||||
public IcdAutoResetEvent(bool initialState) :
|
||||
#if SIMPLSHARP
|
||||
base(new CEvent(true, initialState))
|
||||
#else
|
||||
base(new AutoResetEvent(initialState))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
40
ICD.Common.Utils/IcdManualResetEvent.cs
Normal file
40
ICD.Common.Utils/IcdManualResetEvent.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using ICD.Common.Properties;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
using System.Threading;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies one or more waiting threads that an event has occurred.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class IcdManualResetEvent : AbstractIcdResetEvent
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdManualResetEvent class with the initial state to nonsignaled.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public IcdManualResetEvent() : this(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdManualResetEvent class with a Boolean value indicating whether to set the initial state to signaled.
|
||||
/// </summary>
|
||||
/// <param name="initialState">true to set the initial state signaled; false to set the initial state to nonsignaled.</param>
|
||||
[PublicAPI]
|
||||
public IcdManualResetEvent(bool initialState) :
|
||||
|
||||
#if SIMPLSHARP
|
||||
base(new CEvent(false, initialState))
|
||||
#else
|
||||
base(new ManualResetEvent(initialState))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user