I have a class that wraps ManualResetEvent
(see in the code sample below)
During my application flow I call the WaitOne
method with a 0
parameter a few times.
It returns true
as expected, except for one particular check that returns false
although no exception was thrown and I can clearly see from my logs that the event was set.
Could there be another reason for WaitOne
to return false
?
I will also mention that I have 2 different engines inheriting from the same engine that has a SafeManualResetEvent
member. Lets call them A
and B
.
The flow is that A.SafeManualResetEvent
was set, and a few calls of A.WaitOne(0)
returned true.
Then, B.Set()
is called and completed. Then, A.WaitOne(0)
is called again and returns false
.
After that, all A.WaitOne(0)
and B.WaitOne(0)
return true
as expected.
Is it possible that the two instances of ManualRestEvent
are disturbing each other?
I am adding here a very abstract sample. Please note that the waitOne calls can be from different threads in our app. Please also note that this issue doesn't happen consistently. Out of thousands of users running this app, only one complained about it but we are still struggling to figure out what's different in his environment.
public void Main()
{
PolicyEngine policy = new PolicyEngine();
policy.WaitEngine(); //will return true because initial state is true
policy.LoadEngine();
policy.WaitEngine(); //will return true
FileEngine file = new FileEngine();
policy.WaitEngine(); //will return true
file.LoadEngine();
policy.WaitEngine(); //returns false - unexpected!
policy.WaitEngine(); //returns true
file.WaitEngine(); //returns true
}
public class Engine
{
protected virtual string GetName()
{
return "base";
}
private readonly SafeManualResetEvent _engineLoadedEvent = new SafeManualResetEvent(true);
public Engine()
{
_engineLoadedEvent._name = GetName();
Console.WriteLine("base");
}
public void LoadEngine()
{
_engineLoadedEvent.Reset();
//some code that loads the engine
_engineLoadedEvent.Set();
}
public void WaitEngine()
{
bool result = _engineLoadedEvent.WaitOne(new TimeSpan(0));
Console.WriteLine($"waitOne result is: {result}");
}
}
public class FileEngine : Engine
{
override protected string GetName()
{
return "file";
}
}
public class PolicyEngine : Engine
{
override protected string GetName()
{
return "policy";
}
}
public class SafeManualResetEvent : IDisposable
{
public string _name;
public SafeManualResetEvent(bool initialState)
{
ManualResetEvent = new ManualResetEvent(initialState);
}
public ManualResetEvent ManualResetEvent { get; }
public bool WaitOne(TimeSpan timeout)
{
try
{
Console.WriteLine($"waitOne event for {_name}");
return ManualResetEvent.WaitOne(timeout);
}
catch (ObjectDisposedException)
{
return false;
}
}
public void Reset()
{
try
{
Console.WriteLine($"reset event for {_name}");
ManualResetEvent.Reset();
}
catch (ObjectDisposedException)
{
}
}
public void Set()
{
try
{
Console.WriteLine($"set event for {_name}");
ManualResetEvent.Set();
}
catch (ObjectDisposedException)
{
}
}
public void Dispose()
{
Console.WriteLine($"dispose event for {_name}");
ManualResetEvent.Dispose();
}
}