diff --git a/Source/Core/Runtime/CoyoteRuntime.cs b/Source/Core/Runtime/CoyoteRuntime.cs
index b07a5fc4c..74aa5e968 100644
--- a/Source/Core/Runtime/CoyoteRuntime.cs
+++ b/Source/Core/Runtime/CoyoteRuntime.cs
@@ -133,7 +133,7 @@ internal sealed class CoyoteRuntime : ICoyoteRuntime, IDisposable
///
/// Map from unique controlled thread names to their corresponding operations.
///
- private readonly ConcurrentDictionary ControlledThreads;
+ private readonly ConcurrentDictionary ControlledThreads;
///
/// Map from controlled tasks to their corresponding operations.
@@ -321,7 +321,7 @@ private CoyoteRuntime(Configuration configuration, OperationScheduler scheduler,
this.ThreadPool = new ConcurrentDictionary();
this.OperationMap = new Dictionary();
this.PendingStartOperationMap = new Dictionary();
- this.ControlledThreads = new ConcurrentDictionary();
+ this.ControlledThreads = new ConcurrentDictionary();
this.ControlledTasks = new ConcurrentDictionary();
this.UncontrolledTasks = new ConcurrentDictionary();
this.UncontrolledInvocations = new HashSet();
@@ -584,7 +584,7 @@ internal Thread CreateControlledThread(ControlledOperation op, Delegate logic, A
// TODO: optimize by reusing threads instead of creating a new thread each time?
this.ThreadPool.AddOrUpdate(op.Id, thread, (id, oldThread) => thread);
- this.ControlledThreads.AddOrUpdate(thread.Name, op, (threadName, oldOp) => op);
+ this.ControlledThreads.AddOrUpdate(thread.ManagedThreadId, op, (threadName, oldOp) => op);
return thread;
}
}
@@ -1529,13 +1529,7 @@ internal ControlledOperation GetOperationExecutingOnThread(Thread thread)
{
using (SynchronizedSection.Enter(this.RuntimeLock))
{
- ControlledOperation op = null;
- string name = thread?.Name;
- if (!string.IsNullOrEmpty(name))
- {
- this.ControlledThreads.TryGetValue(name, out op);
- }
-
+ this.ControlledThreads.TryGetValue(thread.ManagedThreadId, out var op);
return op;
}
}
@@ -1833,8 +1827,7 @@ private void StartMonitoringDeadlocks() => Task.Factory.StartNew(this.CheckIfExe
///
private bool IsThreadControlled(Thread thread)
{
- string name = thread?.Name;
- return name != null && this.ControlledThreads.ContainsKey(name);
+ return this.ControlledThreads.ContainsKey(thread.ManagedThreadId);
}
///
diff --git a/Tests/Tests.BugFinding/Threads/ThreadRunTests.cs b/Tests/Tests.BugFinding/Threads/ThreadRunTests.cs
index f8e1fd2a7..527391a0b 100644
--- a/Tests/Tests.BugFinding/Threads/ThreadRunTests.cs
+++ b/Tests/Tests.BugFinding/Threads/ThreadRunTests.cs
@@ -98,5 +98,23 @@ public void TestThreadStartAndJoinStress()
},
configuration: this.GetConfiguration().WithTestingIterations(10));
}
+
+ [Fact(Timeout = 5000)]
+ public void TestThreadRenamed()
+ {
+ this.Test(() =>
+ {
+ bool isDone = false;
+ Thread t = new Thread(() => { isDone = true; });
+ t.Name = "CustomName";
+ t.Start();
+ t.Join();
+
+ Specification.Assert(isDone, "The expected condition was not satisfied.");
+ Specification.Assert(t.ThreadState is ThreadState.Stopped, "State of thread '{0}' is {1} instead of Stopped.",
+ t.ManagedThreadId, t.ThreadState);
+ },
+ configuration: this.GetConfiguration().WithTestingIterations(10));
+ }
}
}