1

I have a series of objects that are all populated from a single thread. The bulk of the flow control is performed in said producer thread. In one or two places I read data out from other threads. Is there an existing diagnostic tool, attribute, etc. that can be used to assert that the creating thread is the only one calling some method so that I can catch programming errors during testing? I would like to avoid complicated class encapsulation to solve this.

public class Datastore
{
   public Register( int id )
   {
       // must be called on producer thread - want to avoid locking 'just in case'. It is an invalid operation to be called from another thread.
   }

   public int GetTotal()
   {
       // can be called on any thread
   }

   // ... more class members, etc.
}

The above is for illustrative purposes only.

Is there an attribute or some kind of pattern that works like this:

public class Datastore
{
   [AssertOnProducerThread]
   public Register( int id )
   {
   }

   public int GetTotal()
   {
   }

   // ... more class members, etc.
}
Steven
  • 619
  • 5
  • 24
  • What exactly are you trying to avoid with multiple threads calling the same method? – DavidG Oct 28 '15 at 18:19
  • @DavidG Imagine the Register function resizes a table, fills it with some data, populates the table entry and returns. The data comes in fast and I want to avoid an unnecessary lock since only one thread should ever write to it. I want to ensure that a future engineer (including myself) doesn't write Datastore.Register() from a different thread five years from now. – Steven Oct 28 '15 at 18:22
  • So would a simple [`lock`](https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx) block work instead? – DavidG Oct 28 '15 at 18:23
  • You may want to consider a model where multiple threads can call a modifying method, but only one thread "wins" (by assigning the new result atomically as a single reference). If you use an immutable data structure, this doesn't even take up additional memory. By using `Interlocked.CompareExchange`, you can also detect race conditions and respond accordingly. (But always, always consider just sticking to a simple `lock`. It's much easier to reason about and *not* inefficient if there is no contention.) – Jeroen Mostert Oct 28 '15 at 18:24
  • @JeroenMostert - I want to catch the error - not handle it. It is a defect that shouldn't be shipped. – Steven Oct 28 '15 at 18:26
  • `if (Interlocked.CompareExchange(ref datastore, newValue, oldValue) != oldValue) throw new InvalidOperationException("Someone else got there first -- this shouldn't happen since I should be the only writer.")` But this does not detect the case where there is no contention. If you want that, you'll have to devise something using the current thread id or a specific cookie and store it -- I see no way around that. – Jeroen Mostert Oct 28 '15 at 18:28
  • 1
    Also, it's not "complicated class encapsulation" to extract an interface that exposes only `GetTotal()` and pass this to consumers instead of the reference itself. There is definitely no magic attribute that somehow tracks on which thread objects were created -- TANSTAAFL. – Jeroen Mostert Oct 28 '15 at 18:35
  • @JeroenMostert I'm not looking for a 'magic' attribute. I'm looking for a diagnostic strategy to help catch these kinds of bugs. Seems like I'll roll me own. Thanks for your input. – Steven Oct 28 '15 at 19:06
  • 1
    @Steven you can see how it is done for ensuring UI-thread access to WinForm/WPF objects... But yes, there is nothing directly available in .Net to implement this painful requirement. – Alexei Levenkov Oct 28 '15 at 20:15
  • @AlexeiLevenkov That's exactly the kind of pattern I am trying to duplicate - thanks for pointing it out. – Steven Oct 28 '15 at 20:52

1 Answers1

1

I am not aware of a diagnostics tool that can automatically do. only thing you can is visual studio debugger that will show the thread id when you hit a breakpoints in those functions. It is better to code it instead of manually checking it by saving the threadid and comparing it with the function and break if false. Or, logging the threadid from the function to a file and post processing the log file.

Getting the thread ID

Community
  • 1
  • 1
Ashburn RK
  • 450
  • 3
  • 8