2016-05-08 3 views
0

Ich habe ein ConcurrentDictionary der Attribute für Produkte. Diese Attribute haben die Produkt-ID und Werte für die Namen des Attributs und alle Optionen, die das Attribut hat. Ich habe dieses ConcurrentDictionary, weil ich Threads habe, die erstellt werden, um jedes Attribut in dem Wörterbuch nach Attributname zu behandeln.Multithread, Linq zu Sql, ConcurrentDictonary Fails Entfernen

if (knownAttribute.AttributeType.Value.Equals("Product Specification")) 
      { 
       Console.WriteLine("Started a thread for: " + knownAttribute.AttributeTypeId + ", " + knownAttribute.Value); 
       while (true) 
       { 

        /* if (AS400SpecificationAttributes.IsEmpty && knownSpecificationBag.IsEmpty && gatherRowsTasks.All(x => x.IsCompleted)) 
         break;*/ 
        AS400SpecificationAttribute AS400SpecificationAttributeWork = null; 
        AS400SpecificationAttributeWork = knownSpecificationBag.Keys.FirstOrDefault(x => x.AttributeName == knownAttribute.Value); 

        if (AS400SpecificationAttributeWork != null) 
        { 
         var product = ctx.Products.FirstOrDefault(x => x.ProductNumber == AS400SpecificationAttributeWork.ProductNumber); 
         if (product == null) 
          continue; 
         var productAttribute = new ProductAttribute(); 
         productAttribute.Attribute = knownAttribute; 
         if (AS400SpecificationAttributeWork.AttributeValue != null) 
         { 
         var knownAttributeOption = ctx.AttributeOptions.FirstOrDefault(x => x.Attribute.Equals(knownAttribute) && x.Value.Equals(AS400SpecificationAttributeWork.AttributeValue)); 

         if (knownAttributeOption == null) 
         { 
          knownAttributeOption = new AttributeOption(); 
          knownAttributeOption.Value = AS400SpecificationAttributeWork.AttributeValue; 
          knownAttributeOption.Attribute = knownAttribute; 
          ctx.AttributeOptions.InsertOnSubmit(knownAttributeOption); 
          ctx.SubmitChanges(); 
         } 
          productAttribute.AttributeOption = knownAttributeOption; 
          productAttribute.AttributeOptionId = knownAttributeOption.Id; 
         } 
         product.ProductAttributes.Add(productAttribute); 
         ctx.SubmitChanges(); 
         string tmpstr = null; 
         if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr)) 
          Thread.Sleep(50); 
        } 
        else 
        { 
         if (tryCounter < 5) 
         { 
          tryCounter++; 
          Thread.Sleep(1000); 
          Console.WriteLine("Thread waiting for work: Product Specification:" + knownAttribute.Value); 
          continue; 
         } 
         else 
         { 
          int outVal; 
          threadTracker.TryRemove("Product Specification:" + knownAttribute.Value, out outVal); 
          Console.WriteLine("Closing Thread: Product Specification:" + knownAttribute.Value); 
          break; 
         } 
        } 
        Thread.Sleep(50); 
       } 

Es scheint, als ob das folgende Attribute-Element nicht entfernt werden soll. enter image description here

Ich verstehe nicht warum. Wenn ich es eine Weile (! Dic.tryRemove (ele)) lege es wird für immer fest und nie von dort bewegen.

Es kann ein Fehler irgendwo innerhalb des Threads sein, aber ich habe keine Ahnung warum.

+0

Ich kann nicht den gesamten Kontext sehen - aber, was passieren würde, wenn das Element nicht im Wörterbuch ist oder wenn zwei Threads beide den gleichen Code ausgeführt haben, also hat einer von ihnen ihn entfernt und für den anderen Thread war er nicht da? –

Antwort

0

Implementieren richtiges equals und GetHashCode wenn TryRemove mit

public override int GetHashCode() 
    { 
     return new { this.name, this.value, this.group, this.productNumber }.GetHashCode(); 
    } 

    public bool Equals(AS400SpecificationAttribute other) 
    { 
     if (other == null) 
      return false; 
     return (this.ProductNumber.Equals(other.productNumber) && ((this.group != null && this.group.Equals(other.AttributeGroup)) || (this.group == null && other.AttributeGroup == null)) && ((this.name!= null && this.name.Equals(other.AttributeName)) || (this.name == null && other.AttributeName == null)) && ((this.value != null && this.value.ToUpper().Equals(other.AttributeValue.ToUpper())) || (this.value == null && other.AttributeValue == null))); 
    } 
0

Diese Aussage

if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr)) 

immer true oder false zurück. Es wird nicht blockiert. Das ist das Verhalten von ConcurrentDictionary. Es wird false zurückgegeben, wenn der Schlüssel nicht im Wörterbuch ist.

Wenn Sie eine Schleife verwenden, während die Methode false zurückgibt und festsitzt, bedeutet dies, dass sich das Element beim Beginn der Schleife nicht im Wörterbuch befindet. Entweder war es entweder nie im Wörterbuch oder ein anderer Thread hat es bereits entfernt.

Möchten Sie die Schleife wiederholen, bis das Element nicht im Wörterbuch ist?
Sie können diese versuchen:

if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr) 
    && !knownSpecificationBag.ContainsKey(AS400SpecificationAttributeWork)) 
+0

Kann das fehlende Element nicht zwischen den Aufrufen von 'TryRemove()' und 'ContainsKey()' hinzugefügt werden? Wird das Rennen nicht weiter vorangetrieben? –

+0

Ich glaube, dass FirstorDefault dieses eine Objekt zurückgibt und die TryRemove weiterhin fehlschlägt und es durch das gleiche Element durchläuft. –