Безопасно ли использовать упакованный тип значения в качестве блокировки для оператора блокировки? - PullRequest
2 голосов
/ 03 июля 2019

Документация оператора lock довольно проста:

lock (x)
{
    // Your code...
}

, где x - это выражение ссылочного типа .

Поэтому мне нельзя разрешать передавать тип значения в качестве блокировщика для lock.Однако я заметил, что могу использовать тип значения, который реализует интерфейс.Другими словами, я могу сделать это:

IDisposable locker = default(DisposableStruct);
lock (locker) Console.WriteLine("Thread safe");

struct DisposableStruct : IDisposable
{
    public void Dispose() { }
}

Это было удивительно.Я понял, что причина в том, что тип значения в штучной упаковке.Согласно документации :

Бокс - это процесс преобразования типа значения в тип object или любого типа интерфейса , реализованный этимтип значения.

Мой вопрос: есть ли какие-либо предостережения с использованием типов значений в штучной упаковке в качестве блокировок для оператора lock.Существует ли какая-либо возможность для оболочки ссылочного типа измениться во время выполнения программы, что приведет к сбою потока-безопасного кода?


Обновление: Вот примерчто беспокоит меняГарантируется ли, что если я выполню код ниже миллиона раз, всегда будет отображаться правильный вывод (1 000 000 000)?

IComparable<int> boxedValueType = 0;
int sharedState = 0;
var tasks = Enumerable.Range(0, 10).Select(_ => Task.Run(() =>
{
    for (int i = 0; i < 100_000_000; i++)
        lock (boxedValueType)
            sharedState++;
})).ToArray();
Task.WaitAll(tasks);
Console.WriteLine(sharedState);
...