2013-07-02 10 views
10

mam kawałek kodu, który działa w ten sposób na liście obiektów OBJ zwane ListofObjects:Dodanie do listy w pętli Parallel.ForEach w THREADSAFE sposób

List<SomeObject> NewListofObjects<SomeObject>(); 

Parallel.ForEach(ListofObjects, obj => 

//Do some operations here on obj to get a newobj 

NewListofObjects.Add(newobj); 

); 

Teraz jestem z równoległym .Dla pętli i chcę wykonać operację na NewListofObjects. Jednak pojawia się ten błąd, gdy próbuję: "Próba odczytu lub zapisu pamięci chronionej często wskazuje, że inna pamięć jest uszkodzona".

Czy to dlatego, że moja metoda NewListofObjects.Add (newobj) nie jest bezpieczna dla wątków? Jeśli tak, w jaki sposób mogę ją chronić w wątkach?

+0

jakie operacje wykonujesz wewnątrz (od obj, aby dostać się do newobj)? – terrybozzio

+0

Długi bałagan operacji, które trudno opisać ... ale wszystkie są zmiennymi lokalnymi utworzonymi w ramach każdej iteracji listy obiektów. Masz jednak rację, pytając o to ... Nie wykluczyłem, że wszystkie operacje wykonywane na obiekcie mogą być również przyczyną tego konkretnego problemu. – Conor

Odpowiedz

26

Czy to dlatego, że moja metoda NewListofObjects.Add(newobj) nie jest bezpieczna dla wątków?

Prawidłowo. To nie jest bezpieczne dla wątków.

Żadna instancja nie ma gwarancji, że będzie bezpieczna dla wątków.

To z MSDN w odniesieniu do List<T> (przejdź do sekcji zatytułowanej "Bezpieczeństwo wątków").

Jeśli tak, w jaki sposób mogę go zabezpieczyć jako gwinty?

Użyj zbieżnej kolekcji, takiej jak ConcurrentBag<T>. Zwróć uwagę, że utracisz możliwość śledzenia kolejności wstawiania przedmiotów.

+0

Na szczęście dla mnie kolejność przedmiotów nie ma znaczenia w moim przypadku. Dzięki! – Conor

+0

W zależności od twoich potrzeb, możesz być w stanie użyć ConcurrentBag do przetworzenia, a następnie zrobić coś w stylu 'var list = bag.OrderBy (p => p.SomeCondition) .ToList();' To może działać lepiej niż blokowanie wokół każdej listy Dodaj. –

14

Możesz użyć bloku locking, jak poniższy kod, aby wstawiać elementy do listy w sposób bezpieczny dla wątków.

var sync = new object(); 
var myNewList = new List<SomeObject>(); 
Parallel.ForEach(myListOfSomethings, a => 
    { 
     // Some other code... 
     var someObj = new SomeObject(); 
     // More other code... 
     lock(sync) 
     { 
      myNewList.Add(someObj); 
     } 
     // Even more code... 
    }); 
+1

Chciałbym móc zaznaczyć wiele poprawnych odpowiedzi, ponieważ rozwiąże to również problem. Dzięki! – Conor

+1

Nie ma problemu! To rozwiązanie zachowuje kolejność dodawanych elementów, ale w twoim przypadku działa tak czy inaczej. Metoda Jasona ma lepszą wydajność. – ajawad987

+0

Czy jest jakiś powód, aby nie blokować myNewList zamiast tego? – Alex