2011-12-29 9 views
5

Implementuję klasę, która będzie używana jednocześnie z wielu wątków. Większość właściwości pobiera i ustawia typy pierwotne, które mogą być obsługiwane poprawnie przez klasę Interlocked. Klasa zawiera właściwość Guid. To nie jest tak proste do wdrożenia w sposób bezpieczny dla wątków. Czy w ten sposób chcesz wdrożyć nieruchomość? Z góry dziękuję.Czy jest to właściwy sposób implementacji wątku bezpiecznego odczytu/zapisu Guid?

private Byte[] _activityId; 
public Guid ActivityId 
    { 
     get { return new Guid(this._activityId); } 
     set 
     { 
      Byte[] bytes = value.ToByteArray(); 
      Interlocked.Exchange(ref this._activityId, bytes); 
     } 
    } 

UPDATE: Tak tylko proponowane rozwiązanie do tej pory nie obejmuje korzystania z wszelkich „Threading” klas lub konstrukcji. Tak więc postawię pytanie, które już zadałem w komentarzach:

Rozumiem, że przypisania typów referencyjnych/prymitywnych mają charakter atomowy, jednak Interlocked gwarantuje, że zmiana jest propagowana do wszystkich wątków. Jeśli moglibyśmy po prostu przypisać wartość, dlaczego Interlocked udostępnia interfejsy API do wymiany typów referencyjnych i wartości pierwotnych?

+3

Przydziały typów referencyjnych są atomowe; nie potrzebujesz "Interlocked". – SLaks

+1

Jest bardzo możliwe, że czegoś tu brakuje, ale ponieważ Guids są typami wartości, jaki jest dokładnie ten problem? –

+0

Jaki jest sens posiadania właściwości 'byte []' i publicznej właściwości 'Guid'? Jak ten kod będzie używany? –

Odpowiedz

2

Myślę, że można użyć innego przeciążenie Interlocked.Exchange:

private volatile object _activityId; // Yes, object :) 
public Guid ActivityId { 
    get { return (Guid)_activityId; } 
    set { _activityId = value; } 
} 

To działa, ponieważ Guid jest teraz zapakowane i przyporządkowanie typów referencyjnych jest atomowy.

+1

To nie skompiluje; potrzebujesz obsady. Ponadto nadal nie potrzebujesz "Interlocked". – SLaks

+1

@SLaks Masz rację - dodałem obsadę, usunąłem Exchange i dodałem szybkie wyjaśnienie. Dziękuję za spostrzeżenie błędu (powinienem wkleić kopię z mojego edytora, zamiast ponownie pisać z brakującym obsadą). – dasblinkenlight

+0

Wygląda na to, że może zwrócić nieaktualne wartości z gettera. – CodesInChaos

4

można dostać taniej zadanie atomową tworząc własne klasy etui:

class Box<T> where T : struct { 
    public readonly T Value; 
    public Box(T value) { Value = value; } 
} 

Dzięki przechowywaniu odniesienie do (niezmiennej) Box przykład zamiast przechowywania wartości bezpośrednio, wszystkie operacje na polu będzie atomowy .

private Box<Guid> _activityId; 
public Guid ActivityId { 
    get { return this._activityId.Value; } 
    set { this._activityId = new Box<Guid>(value); } 
} 

ten sposób, że zakaz atomowe operacje kopiowania struct zdarzyć w new Box<Guid>(value) i w dostępie .Value. Ponieważ nie obejmują one pola, nie spowodują problemów.

Powinno to być znacznie szybsze niż użycie tablic bajtowych i nieco szybsze niż rodzimy boks z rzutem. (zrzeczenie się: nie mierzyłem)

+0

Jak to jest, że nie ma potrzeby blokowania - lub - niestabilnego modyfikatora -lub- jakiegoś innego konstruktu/klasy "Theading"? – Josh

+1

Ponieważ przypisania referencyjne są atomowe. Możesz chcieć 'Thread.MemoryBarrier()'; Nie jestem pewny. – SLaks

+0

@SLaks: Funkcja MemoryBarrier() jest ważna dla zagwarantowania zamówienia lub upewnienia się, że pętla nie optymalizuje ładowania wartości z pamięci zamiast sprawdzania rejestru. Powinieneś być poprawny w swojej odpowiedzi. – Bengie

Powiązane problemy