Is HashSet thread safe as a value of ConcurrentDictionary<TKey, HashSet>?












4















If I have the following code:



var dictionary = new ConcurrentDictionary<int, HashSet<string>>();

foreach (var user in users)
{
if (!dictionary.ContainsKey(user.GroupId))
{
dictionary.TryAdd(user.GroupId, new HashSet<string>());
}

dictionary[user.GroupId].Add(user.Id.ToString());
}


Is the act of adding an item into the HashSet inherently thread safe because HashSet is a value property of the concurrent dictionary?










share|improve this question





























    4















    If I have the following code:



    var dictionary = new ConcurrentDictionary<int, HashSet<string>>();

    foreach (var user in users)
    {
    if (!dictionary.ContainsKey(user.GroupId))
    {
    dictionary.TryAdd(user.GroupId, new HashSet<string>());
    }

    dictionary[user.GroupId].Add(user.Id.ToString());
    }


    Is the act of adding an item into the HashSet inherently thread safe because HashSet is a value property of the concurrent dictionary?










    share|improve this question



























      4












      4








      4








      If I have the following code:



      var dictionary = new ConcurrentDictionary<int, HashSet<string>>();

      foreach (var user in users)
      {
      if (!dictionary.ContainsKey(user.GroupId))
      {
      dictionary.TryAdd(user.GroupId, new HashSet<string>());
      }

      dictionary[user.GroupId].Add(user.Id.ToString());
      }


      Is the act of adding an item into the HashSet inherently thread safe because HashSet is a value property of the concurrent dictionary?










      share|improve this question
















      If I have the following code:



      var dictionary = new ConcurrentDictionary<int, HashSet<string>>();

      foreach (var user in users)
      {
      if (!dictionary.ContainsKey(user.GroupId))
      {
      dictionary.TryAdd(user.GroupId, new HashSet<string>());
      }

      dictionary[user.GroupId].Add(user.Id.ToString());
      }


      Is the act of adding an item into the HashSet inherently thread safe because HashSet is a value property of the concurrent dictionary?







      c# multithreading concurrentdictionary






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 '18 at 0:44









      Camilo Terevinto

      18.4k63666




      18.4k63666










      asked Nov 20 '18 at 0:16









      MarkoMarko

      7,23453041




      7,23453041
























          3 Answers
          3






          active

          oldest

          votes


















          4














          No, the collection (the dictionary itself) is thread-safe, not whatever you put in it. You have a couple of options:





          1. Use AddOrUpdate as @TheGeneral mentioned:



            dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());



          2. Use a concurrent collection, like the ConcurrentBag<T>:



            ConcurrentDictionary<int, ConcurrentBag<string>>



          Whenever you are building the Dictionary, as in your code, you should be better off accessing it as little as possible. Think of something like this:



          var dictionary = new ConcurrentDictionary<int, ConcurrentBag<string>>();
          var grouppedUsers = users.GroupBy(u => u.GroupId);

          foreach (var group in grouppedUsers)
          {
          // get the bag from the dictionary or create it if it doesn't exist
          var currentBag = dictionary.GetOrAdd(group.Key, new ConcurrentBag<string>());

          // load it with the users required
          foreach (var user in group)
          {
          if (!currentBag.Contains(user.Id.ToString())
          {
          currentBag.Add(user.Id.ToString());
          }
          }
          }



          1. If you actually want a built-in concurrent HashSet-like collection, you'd need to use ConcurrentDictionary<int, ConcurrentDictionary<string, string>>, and care either about the key or the value from the inner one.






          share|improve this answer


























          • Oh now I get the ConcurrentBag comment.

            – Joshua
            Nov 20 '18 at 0:35











          • Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

            – Marko
            Nov 20 '18 at 0:38











          • @Marko No, it behaves more like a concurrent list

            – Camilo Terevinto
            Nov 20 '18 at 0:41











          • @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

            – Marko
            Nov 20 '18 at 1:08





















          5














          No. Putting a container in a thread-safe container does not make the inner container thread safe.



          dictionary[user.GroupId].Add(user.Id.ToString());


          is calling HashSet's add after retrieving it from the ConcurrentDictionary. If this GroupId is looked up from two threads at once this would break your code with strange failure modes. I saw the result of one of my teammates making the mistake of not locking his sets, and it wasn't pretty.



          This is a plausible solution. I'd do something different myself but this is closer to your code.



          if (!dictionary.ContainsKey(user.GroupId)
          {
          dictionary.TryAdd(user.GroupId, new HashSet<string>());
          }
          var groups = dictionary[user.GroupId];
          lock(groups)
          {
          groups.Add(user.Id.ToString())
          }





          share|improve this answer


























          • You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

            – Michael Randall
            Nov 20 '18 at 0:34













          • @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

            – Marko
            Nov 20 '18 at 1:14











          • @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

            – Joshua
            Nov 20 '18 at 1:23



















          1














          Using a ConcurrentDictionary like this is not thread safe



          dictionary[user.GroupId].Add(user.Id.ToString());


          instead use



          AddOrUpdate(TKey, TValue, Func)



          dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());


          Or as Camilo Terevinto said ConcurrentBag is probably where you want to be






          share|improve this answer
























          • AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

            – Camilo Terevinto
            Nov 20 '18 at 0:26











          • @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

            – Michael Randall
            Nov 20 '18 at 0:27













          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384465%2fis-hashsett-thread-safe-as-a-value-of-concurrentdictionarytkey-hashsett%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          4














          No, the collection (the dictionary itself) is thread-safe, not whatever you put in it. You have a couple of options:





          1. Use AddOrUpdate as @TheGeneral mentioned:



            dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());



          2. Use a concurrent collection, like the ConcurrentBag<T>:



            ConcurrentDictionary<int, ConcurrentBag<string>>



          Whenever you are building the Dictionary, as in your code, you should be better off accessing it as little as possible. Think of something like this:



          var dictionary = new ConcurrentDictionary<int, ConcurrentBag<string>>();
          var grouppedUsers = users.GroupBy(u => u.GroupId);

          foreach (var group in grouppedUsers)
          {
          // get the bag from the dictionary or create it if it doesn't exist
          var currentBag = dictionary.GetOrAdd(group.Key, new ConcurrentBag<string>());

          // load it with the users required
          foreach (var user in group)
          {
          if (!currentBag.Contains(user.Id.ToString())
          {
          currentBag.Add(user.Id.ToString());
          }
          }
          }



          1. If you actually want a built-in concurrent HashSet-like collection, you'd need to use ConcurrentDictionary<int, ConcurrentDictionary<string, string>>, and care either about the key or the value from the inner one.






          share|improve this answer


























          • Oh now I get the ConcurrentBag comment.

            – Joshua
            Nov 20 '18 at 0:35











          • Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

            – Marko
            Nov 20 '18 at 0:38











          • @Marko No, it behaves more like a concurrent list

            – Camilo Terevinto
            Nov 20 '18 at 0:41











          • @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

            – Marko
            Nov 20 '18 at 1:08


















          4














          No, the collection (the dictionary itself) is thread-safe, not whatever you put in it. You have a couple of options:





          1. Use AddOrUpdate as @TheGeneral mentioned:



            dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());



          2. Use a concurrent collection, like the ConcurrentBag<T>:



            ConcurrentDictionary<int, ConcurrentBag<string>>



          Whenever you are building the Dictionary, as in your code, you should be better off accessing it as little as possible. Think of something like this:



          var dictionary = new ConcurrentDictionary<int, ConcurrentBag<string>>();
          var grouppedUsers = users.GroupBy(u => u.GroupId);

          foreach (var group in grouppedUsers)
          {
          // get the bag from the dictionary or create it if it doesn't exist
          var currentBag = dictionary.GetOrAdd(group.Key, new ConcurrentBag<string>());

          // load it with the users required
          foreach (var user in group)
          {
          if (!currentBag.Contains(user.Id.ToString())
          {
          currentBag.Add(user.Id.ToString());
          }
          }
          }



          1. If you actually want a built-in concurrent HashSet-like collection, you'd need to use ConcurrentDictionary<int, ConcurrentDictionary<string, string>>, and care either about the key or the value from the inner one.






          share|improve this answer


























          • Oh now I get the ConcurrentBag comment.

            – Joshua
            Nov 20 '18 at 0:35











          • Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

            – Marko
            Nov 20 '18 at 0:38











          • @Marko No, it behaves more like a concurrent list

            – Camilo Terevinto
            Nov 20 '18 at 0:41











          • @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

            – Marko
            Nov 20 '18 at 1:08
















          4












          4








          4







          No, the collection (the dictionary itself) is thread-safe, not whatever you put in it. You have a couple of options:





          1. Use AddOrUpdate as @TheGeneral mentioned:



            dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());



          2. Use a concurrent collection, like the ConcurrentBag<T>:



            ConcurrentDictionary<int, ConcurrentBag<string>>



          Whenever you are building the Dictionary, as in your code, you should be better off accessing it as little as possible. Think of something like this:



          var dictionary = new ConcurrentDictionary<int, ConcurrentBag<string>>();
          var grouppedUsers = users.GroupBy(u => u.GroupId);

          foreach (var group in grouppedUsers)
          {
          // get the bag from the dictionary or create it if it doesn't exist
          var currentBag = dictionary.GetOrAdd(group.Key, new ConcurrentBag<string>());

          // load it with the users required
          foreach (var user in group)
          {
          if (!currentBag.Contains(user.Id.ToString())
          {
          currentBag.Add(user.Id.ToString());
          }
          }
          }



          1. If you actually want a built-in concurrent HashSet-like collection, you'd need to use ConcurrentDictionary<int, ConcurrentDictionary<string, string>>, and care either about the key or the value from the inner one.






          share|improve this answer















          No, the collection (the dictionary itself) is thread-safe, not whatever you put in it. You have a couple of options:





          1. Use AddOrUpdate as @TheGeneral mentioned:



            dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());



          2. Use a concurrent collection, like the ConcurrentBag<T>:



            ConcurrentDictionary<int, ConcurrentBag<string>>



          Whenever you are building the Dictionary, as in your code, you should be better off accessing it as little as possible. Think of something like this:



          var dictionary = new ConcurrentDictionary<int, ConcurrentBag<string>>();
          var grouppedUsers = users.GroupBy(u => u.GroupId);

          foreach (var group in grouppedUsers)
          {
          // get the bag from the dictionary or create it if it doesn't exist
          var currentBag = dictionary.GetOrAdd(group.Key, new ConcurrentBag<string>());

          // load it with the users required
          foreach (var user in group)
          {
          if (!currentBag.Contains(user.Id.ToString())
          {
          currentBag.Add(user.Id.ToString());
          }
          }
          }



          1. If you actually want a built-in concurrent HashSet-like collection, you'd need to use ConcurrentDictionary<int, ConcurrentDictionary<string, string>>, and care either about the key or the value from the inner one.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 20 '18 at 0:41

























          answered Nov 20 '18 at 0:34









          Camilo TerevintoCamilo Terevinto

          18.4k63666




          18.4k63666













          • Oh now I get the ConcurrentBag comment.

            – Joshua
            Nov 20 '18 at 0:35











          • Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

            – Marko
            Nov 20 '18 at 0:38











          • @Marko No, it behaves more like a concurrent list

            – Camilo Terevinto
            Nov 20 '18 at 0:41











          • @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

            – Marko
            Nov 20 '18 at 1:08





















          • Oh now I get the ConcurrentBag comment.

            – Joshua
            Nov 20 '18 at 0:35











          • Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

            – Marko
            Nov 20 '18 at 0:38











          • @Marko No, it behaves more like a concurrent list

            – Camilo Terevinto
            Nov 20 '18 at 0:41











          • @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

            – Marko
            Nov 20 '18 at 1:08



















          Oh now I get the ConcurrentBag comment.

          – Joshua
          Nov 20 '18 at 0:35





          Oh now I get the ConcurrentBag comment.

          – Joshua
          Nov 20 '18 at 0:35













          Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

          – Marko
          Nov 20 '18 at 0:38





          Does ConcurrentBag behave as HashSet in other words it does not allow for duplicates in the list?

          – Marko
          Nov 20 '18 at 0:38













          @Marko No, it behaves more like a concurrent list

          – Camilo Terevinto
          Nov 20 '18 at 0:41





          @Marko No, it behaves more like a concurrent list

          – Camilo Terevinto
          Nov 20 '18 at 0:41













          @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

          – Marko
          Nov 20 '18 at 1:08







          @CamiloTerevinto The only problem I see with ConcurrentBag is how can I remove items from the bag? There is no Remove... looks like I need to use TryTake?

          – Marko
          Nov 20 '18 at 1:08















          5














          No. Putting a container in a thread-safe container does not make the inner container thread safe.



          dictionary[user.GroupId].Add(user.Id.ToString());


          is calling HashSet's add after retrieving it from the ConcurrentDictionary. If this GroupId is looked up from two threads at once this would break your code with strange failure modes. I saw the result of one of my teammates making the mistake of not locking his sets, and it wasn't pretty.



          This is a plausible solution. I'd do something different myself but this is closer to your code.



          if (!dictionary.ContainsKey(user.GroupId)
          {
          dictionary.TryAdd(user.GroupId, new HashSet<string>());
          }
          var groups = dictionary[user.GroupId];
          lock(groups)
          {
          groups.Add(user.Id.ToString())
          }





          share|improve this answer


























          • You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

            – Michael Randall
            Nov 20 '18 at 0:34













          • @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

            – Marko
            Nov 20 '18 at 1:14











          • @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

            – Joshua
            Nov 20 '18 at 1:23
















          5














          No. Putting a container in a thread-safe container does not make the inner container thread safe.



          dictionary[user.GroupId].Add(user.Id.ToString());


          is calling HashSet's add after retrieving it from the ConcurrentDictionary. If this GroupId is looked up from two threads at once this would break your code with strange failure modes. I saw the result of one of my teammates making the mistake of not locking his sets, and it wasn't pretty.



          This is a plausible solution. I'd do something different myself but this is closer to your code.



          if (!dictionary.ContainsKey(user.GroupId)
          {
          dictionary.TryAdd(user.GroupId, new HashSet<string>());
          }
          var groups = dictionary[user.GroupId];
          lock(groups)
          {
          groups.Add(user.Id.ToString())
          }





          share|improve this answer


























          • You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

            – Michael Randall
            Nov 20 '18 at 0:34













          • @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

            – Marko
            Nov 20 '18 at 1:14











          • @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

            – Joshua
            Nov 20 '18 at 1:23














          5












          5








          5







          No. Putting a container in a thread-safe container does not make the inner container thread safe.



          dictionary[user.GroupId].Add(user.Id.ToString());


          is calling HashSet's add after retrieving it from the ConcurrentDictionary. If this GroupId is looked up from two threads at once this would break your code with strange failure modes. I saw the result of one of my teammates making the mistake of not locking his sets, and it wasn't pretty.



          This is a plausible solution. I'd do something different myself but this is closer to your code.



          if (!dictionary.ContainsKey(user.GroupId)
          {
          dictionary.TryAdd(user.GroupId, new HashSet<string>());
          }
          var groups = dictionary[user.GroupId];
          lock(groups)
          {
          groups.Add(user.Id.ToString())
          }





          share|improve this answer















          No. Putting a container in a thread-safe container does not make the inner container thread safe.



          dictionary[user.GroupId].Add(user.Id.ToString());


          is calling HashSet's add after retrieving it from the ConcurrentDictionary. If this GroupId is looked up from two threads at once this would break your code with strange failure modes. I saw the result of one of my teammates making the mistake of not locking his sets, and it wasn't pretty.



          This is a plausible solution. I'd do something different myself but this is closer to your code.



          if (!dictionary.ContainsKey(user.GroupId)
          {
          dictionary.TryAdd(user.GroupId, new HashSet<string>());
          }
          var groups = dictionary[user.GroupId];
          lock(groups)
          {
          groups.Add(user.Id.ToString())
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 20 '18 at 0:34

























          answered Nov 20 '18 at 0:27









          JoshuaJoshua

          23k548101




          23k548101













          • You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

            – Michael Randall
            Nov 20 '18 at 0:34













          • @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

            – Marko
            Nov 20 '18 at 1:14











          • @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

            – Joshua
            Nov 20 '18 at 1:23



















          • You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

            – Michael Randall
            Nov 20 '18 at 0:34













          • @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

            – Marko
            Nov 20 '18 at 1:14











          • @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

            – Joshua
            Nov 20 '18 at 1:23

















          You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

          – Michael Randall
          Nov 20 '18 at 0:34







          You are correct, however exclusively using the func methods will, though i think there are better solutions to this problem

          – Michael Randall
          Nov 20 '18 at 0:34















          @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

          – Marko
          Nov 20 '18 at 1:14





          @Joshua Why do you say that you would do something different? What's wrong with locking the hash set like this? Is there a better way to do it?

          – Marko
          Nov 20 '18 at 1:14













          @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

          – Joshua
          Nov 20 '18 at 1:23





          @Marko At work we have a more powerful primitive to build this from. The locking isn't bad, it's just slightly suboptimal and a lot easier to understand.

          – Joshua
          Nov 20 '18 at 1:23











          1














          Using a ConcurrentDictionary like this is not thread safe



          dictionary[user.GroupId].Add(user.Id.ToString());


          instead use



          AddOrUpdate(TKey, TValue, Func)



          dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());


          Or as Camilo Terevinto said ConcurrentBag is probably where you want to be






          share|improve this answer
























          • AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

            – Camilo Terevinto
            Nov 20 '18 at 0:26











          • @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

            – Michael Randall
            Nov 20 '18 at 0:27


















          1














          Using a ConcurrentDictionary like this is not thread safe



          dictionary[user.GroupId].Add(user.Id.ToString());


          instead use



          AddOrUpdate(TKey, TValue, Func)



          dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());


          Or as Camilo Terevinto said ConcurrentBag is probably where you want to be






          share|improve this answer
























          • AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

            – Camilo Terevinto
            Nov 20 '18 at 0:26











          • @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

            – Michael Randall
            Nov 20 '18 at 0:27
















          1












          1








          1







          Using a ConcurrentDictionary like this is not thread safe



          dictionary[user.GroupId].Add(user.Id.ToString());


          instead use



          AddOrUpdate(TKey, TValue, Func)



          dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());


          Or as Camilo Terevinto said ConcurrentBag is probably where you want to be






          share|improve this answer













          Using a ConcurrentDictionary like this is not thread safe



          dictionary[user.GroupId].Add(user.Id.ToString());


          instead use



          AddOrUpdate(TKey, TValue, Func)



          dictionary.AddOrUpdate(user.GroupId,  new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());


          Or as Camilo Terevinto said ConcurrentBag is probably where you want to be







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 20 '18 at 0:23









          Michael RandallMichael Randall

          30.6k63465




          30.6k63465













          • AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

            – Camilo Terevinto
            Nov 20 '18 at 0:26











          • @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

            – Michael Randall
            Nov 20 '18 at 0:27





















          • AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

            – Camilo Terevinto
            Nov 20 '18 at 0:26











          • @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

            – Michael Randall
            Nov 20 '18 at 0:27



















          AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

          – Camilo Terevinto
          Nov 20 '18 at 0:26





          AddOrUpdate should work, but, wouldn't it be better to construct the entire group instead of accessing the dictionary for each user? Also, if it's a variable, and not a class field/property, it shouldn't make a difference, should it?

          – Camilo Terevinto
          Nov 20 '18 at 0:26













          @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

          – Michael Randall
          Nov 20 '18 at 0:27







          @CamiloTerevinto yeah you are correct, i ignored all the code. I am a bit busy, if you make an answer ill upvote and remove this

          – Michael Randall
          Nov 20 '18 at 0:27




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384465%2fis-hashsett-thread-safe-as-a-value-of-concurrentdictionarytkey-hashsett%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

          ComboBox Display Member on multiple fields

          Is it possible to collect Nectar points via Trainline?