Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing Threads for equality

I am looking for a way to explain that it's unreasonable to sprinkle high-level business logic with calls to ReferenceEquals().

Here's a code snippet that I have a problem with (precondition in a method, designed to throw if we're on a wrong thread):

if (!object.ReferenceEquals(Thread.CurrentThread, RequestHandlerThread))

Is it reliable to write this instead:

if (Thread.CurrentThread != RequestHandlerThread)

I suggested to use ManagedThreadIds in the comparison based on what I commonly see in tutorials. Adversary says that comparison for reference equality seems more object-oriented.

Here's (roughly) what I saw in Reflector's view of System.Object with .NET 4.0. Keep in mind that Thread class is sealed, and has no overload for operator==.

public static bool ReferenceEquals(object objA, object objB)
{
    return (objA == objB);
}

public static bool Equals(object objA, object objB)
{
    return (objA == objB || 
        (objA != null && objB != null && objA.Equals(objB)));
}

Here are some basic tests, verifying operation on thread pool... Did I miss any significant tests?

using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ConsoleApplicationX
{
   class Program
   {
      static readonly Thread mainThread;

      static Program()
      {
         mainThread = Thread.CurrentThread;
      }

      static void Main(string[] args)
      {
         Thread thread = Thread.CurrentThread;
         if (thread != Thread.CurrentThread)
            Debug.Fail("");

         if(Thread.CurrentThread != thread)
            Debug.Fail("");

         if (thread != mainThread)
            Debug.Fail("");

         var task = Task.Factory.StartNew(() => RunOnBackground(thread));
         task.Wait();

         var anotherThread = new Thread(new ParameterizedThreadStart(RunInAnotherThread));
         anotherThread.Start(thread);
      }

      static void RunOnBackground(Thread fromInitial)
      {
         if (Thread.CurrentThread == fromInitial)
            Debug.Fail("");

         if (fromInitial != mainThread)
            Debug.Fail("");
      }

      static void RunInAnotherThread(object fromInitialAsObject)
      {
         var fromInitial = (Thread)fromInitialAsObject;

         if (Thread.CurrentThread == fromInitial)
            Debug.Fail("");

         if (fromInitial != mainThread)
            Debug.Fail("");
      }
   }
}
like image 246
GregC Avatar asked Jul 10 '26 13:07

GregC


2 Answers

Trying not to preach, but ... In general, if there is an identity property to use, in this case

Thread.ManagedThreadId

it should be used for equality comparisons unless there is a performance constraint for the executing code. The semantics of a pointer comparison are a lot different than equality. Also, the pointer comparison is dependent upon the implementation of Thread in mscorlib.

like image 192
KeithP Avatar answered Jul 13 '26 11:07

KeithP


You are correct. As your reflection inquiry shows, the two ways are equivalent (barring an extra method call in the adversary's way)

like image 21
Attila Avatar answered Jul 13 '26 11:07

Attila