Это правильный способ реализовать потоковое свойство чтения / записи Guid? - PullRequest
6 голосов
/ 29 декабря 2011

Я реализую класс, который будет использоваться одновременно из нескольких потоков. Большинство свойств получают и устанавливают примитивные типы, которые могут правильно обрабатываться классом Interlocked. Класс включает свойство Guid. Это не так просто реализовать в поточно-ориентированном виде. Это как вы бы реализовали свойство? Заранее спасибо.

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

ОБНОВЛЕНИЕ: Таким образом, единственное предлагаемое решение до этого момента не включает использование каких-либо классов или конструкций Threading. Итак, я собираюсь поставить вопрос, который я уже задал в комментариях:

Насколько я понимаю, назначения типов ссылочных / примитивных значений являются атомарными, однако Interlocked гарантирует, что изменение распространяется на все потоки. Если бы мы могли просто присвоить значение, почему Interlocked предоставляет API для обмена ссылочными типами и примитивными значениями?

Ответы [ 2 ]

4 голосов
/ 29 декабря 2011

Вы можете получить более дешевое атомное назначение, создав собственный класс коробки:

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

Сохраняя ссылку на (неизменяемый) экземпляр Box вместо непосредственного хранения значения, все операции над полем будут атомарными.

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

Таким образом, неатомарные операции копирования структуры происходят в new Box<Guid>(value) и в доступе .Value. Так как они не задействуют поле, они не вызовут проблем.

Это должно быть намного быстрее, чем использование байтовых массивов, и немного быстрее, чем собственный бокс с приведением. (отказ от ответственности: я не измерял)

2 голосов
/ 29 декабря 2011

Я думаю, вы могли бы использовать другую перегрузку Interlocked.Exchange:

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

Это работает, потому что Guid теперь в штучной упаковке, и назначение ссылочных типов является атомарным.

...