Что такое потокобезопасный способ чтения/записи свойства С# в классе?

Я новичок в С#. В Java я могу сделать чтение/запись члена класса Java, используя "синхронизированное" ключевое слово в методе setter/getter.

Не могли бы вы рассказать мне, как правильно сделать то же самое в С#? В С# нет синхронизированного ключевого слова. Должен ли я использовать аннотацию [MethodImpl (MethodImplOptions.Synchronized)], упомянутую в С# версии синхронизированного ключевого слова java??

Или использовать Monitor.Enter(и впоследствии Monitor.Exit)?

Ответ 1

Используйте Monitor.Enter/Exit (или lock - синтаксический сахар для Monitor) с полем private object _lock = new object().

Не используйте MethodImplOptions.Synchronized. Он блокируется на this, поэтому возможно, что какой-либо другой код будет заблокирован на том же экземпляре, который вызывает взаимоблокировки.

Блокировка экземпляра или типа, как и в случае с синхронизированным флагом, не рекомендуется для общедоступных типов, поскольку код, отличный от вашего собственного, может принимать блокировки для общедоступных типов и экземпляров. Это может вызвать взаимоблокировки или другие проблемы синхронизации.

Ответ 2

В некоторых сценариях volatile может быть достаточно (хотя это зависит от того, что вы защищаете и что такое тип данных):

private volatile int _counter;
public int Counter
{
    get { return _counter; }
    set { _counter = value; }            
}

ИЛИ lock it

#region public int Counter { set; get; }
private int _counter;
private object sync_counter = new object();
public int Counter
{
    set
    {
        lock(sync_counter)
        {
            _counter = value;
        }
    }
    get
    {
        lock(sync_counter)
        {
            return _counter;
        }
    }
}
#endregion

Ответ 3

Как сказал Лорц, лучший способ - использовать блокировку

public class ThreadSafeSetters
{
    private bool _foo;
    private object _locker = new object();

    public bool Foo
    {
        get
        {
            lock (_locker)
            {
                return _foo;
            }
        }
        set
        {
            lock (_locker)
            {
                _foo = value;
            }
        }
    }
}