0

I have a strange situation. I am using a variant of BiDictionary<mystruct, int> implementation here.. I also use the Dictionary type to ConcurrentDictionary for firstToSecond

The problem is that at the code

 ConcurrentDictionary firstToSecond;

  public IList<TSecond> GetByFirst(TFirst first)
{
    IList<TSecond> list;
    var myclone=DeepCopy(firstToSecond);
    var res =firstToSecond.TryGetValue(first, out list);
    if (!res)
    {
        return EmptySecondList;
    }
    var doNextThing = DoNextMethod();
    return new List<TSecond>(list); // Create a copy for sanity
}

may sometimes have res=false. When such a condition occurs, I naturally break at the next statement (var doNextThing = DoNextMethod();) in my Visual Studio 2015 debugger to examine the value. I put mydict.TryGetValue(item, out index) in the debugging window and to my puzzlement, now it does return a value ( ie: res=true)!

Debugging attempt:

  1. I make sure that my key is sane(it is a struct, so it should be of an immutable type with an .Equals() and .GetHashCode() that do repeatable, predictable things).

  2. I also deepcopy mydict to another object ( say, myclone) before I carry out the TryGetValue operation. I check the myclone.TryGetValue(item, out index) in the debugger, and it returns true!

  3. I suspect this is a multithreading issue, because my code does multithreading. So, I then check whether myDict is being modified by other thread in my code, and I find that it is being instantiated and used inside a class, and inside a private method (firstToSecond is private). It is definitely not a singleton that is accessible from elsewhere, let alone being modified.

    1. I use ConcurrentDictionary for firstToSecond variable.

My multithreading debugging skill is very limited, so I don't know how else I can test for multithreading issue. Any ideas how I can tackle the issue?

This is not a dupe of this question! For I am aware that there is a ConcurrentDictionary, but how it can be useful?

Graviton
  • 81,782
  • 146
  • 424
  • 602
  • What is the type of 'item' parameter – Ashley Pillay Aug 08 '17 at 11:13
  • 1
    you would need to use locking – Ehsan Sajjad Aug 08 '17 at 11:14
  • As a sanity check, insert a tracepoint at the statement to dump the values of `res`, `item` and `index`, just before the breakpoint at `doNextThing`. Also make sure your key is sane (`item` should be of an immutable type with an `.Equals()` and `.GetHashCode()` that do repeatable, predictable things). – Jeroen Mostert Aug 08 '17 at 11:18
  • I don't think this is a *not* duplicate; see the updated question, so please, reopen! – Graviton Aug 08 '17 at 11:21
  • If this is not a duplicate, what issue are you trying to tackle? Since the duplicate explains why you need a thread-safe dictionary. – Patrick Hofman Aug 08 '17 at 11:23
  • 1
    Either your dictionary *is* used concurrently, or it *isn't*. The simplest way to ensure it *isn't* is to make sure that's impossible, which means that aside from being a private field, it should never be passed as a parameter to any method outside the class, and your class should never start threads or tasks (that use the dictionary). If you have ensured that, you know your issue has nothing to do with threading. If it *does*, thread-safe access is your only recourse. – Jeroen Mostert Aug 08 '17 at 11:24
  • 1
    Does your code run with multiple threads? – DavidG Aug 08 '17 at 11:25
  • @JeroenMostert, see the updated question. To answer your question, the dictionary is a private field, and even though I do use multi threading, I am not sure how multi threading can affect the result. – Graviton Aug 08 '17 at 11:38
  • @DavidG, yes, my code runs with multithread, but I don't see how it can interfere there – Graviton Aug 08 '17 at 11:41
  • Are you asking what concurrency / race conditions are? – Patrick Hofman Aug 08 '17 at 11:42
  • @PatrickHofman, yes.. that will be helpful to me – Graviton Aug 08 '17 at 11:43
  • 1
    The question isn't "do you use more than one thread", it's "is there any way this dictionary is accessible from another thread". The mere *existence* of other threads is irrelevant, it's whether they have any access path to the dictionary. If they don't, then concurrency isn't the problem and you can eliminate it from consideration. – Jeroen Mostert Aug 08 '17 at 11:44
  • @JeroenMostert, I have changed the type to ConcurrentDictionary, yet the same problem persists – Graviton Aug 08 '17 at 11:47
  • Just a note from personal experience - even if concurrency is not the real problem, it sometimes messes with my debugging. I might accidentally overlook the fact that I'm hitting breakpoints in different instances because of thread switching. – Michal S Aug 08 '17 at 11:48
  • @Graviton: Of course it would, if concurrency were an issue! `ConcurrentDictionary` merely makes it *safe* to modify the dictionary from multiple places. It would in no way prevent thread #2 from changing the dictionary right after thread #1 checked it -- that would require exclusion (through a lock). There is no silver bullet for fixing threading issues. First understand what's going on, then consider how to possibly fix it. – Jeroen Mostert Aug 08 '17 at 11:49
  • @JeroenMostert, like I mention above, I performed a deep copy of the original dictionary to another object, and then I perform TryGetValue check against both dictionary instance, but of them returns true in the debugging window – Graviton Aug 08 '17 at 11:52
  • "Deep copy" doesn't natively exist in the .NET Framework except for a very limited set of types, so however you're doing your deep copy needs a close look as well. I suspect a plain, old, boring bug somewhere, nothing to do with concurrency. But debugging from a distance is no easy thing to do. – Jeroen Mostert Aug 08 '17 at 11:53
  • @JeroenMostert, what could be the problem? – Graviton Aug 08 '17 at 11:54
  • Are you sure your deep copy is actually creating copies and not just leaving original references in the copied list? – DavidG Aug 08 '17 at 11:55
  • @Graviton: "It is a capital mistake to theorize before one has data. Insensibly one begins to twist facts to suit theories, instead of theories to suit facts." Basically this is going to take a game of 20 (or more) questions while we peel all the details out of you that could possibly be relevant, or you posting all your code. This is better suited to a chat room than a comment chain. – Jeroen Mostert Aug 08 '17 at 11:57
  • It's not often you see an Arthur Conan Doyle quote on Stack Overflow, nice! – DavidG Aug 08 '17 at 11:59

0 Answers0