Я прочитал всю документацию о потокобезопасных типах и инструкции "lock", но я до сих пор не получаю ее на 100%.
Когда мне нужно использовать инструкцию "lock"? Как это относится к (не) потокобезопасным типам? Спасибо.
Я прочитал всю документацию о потокобезопасных типах и инструкции "lock", но я до сих пор не получаю ее на 100%.
Когда мне нужно использовать инструкцию "lock"? Как это относится к (не) потокобезопасным типам? Спасибо.
Представьте экземпляр класса с глобальной переменной. Представьте, что два потока вызывают метод на этом объекте в одно и то же время, и этот метод обновляет глобальную переменную внутри.
Вероятность того, что значение в переменной будет искажено. Различные языки и компиляторы/переводчики будут иметь дело с этим по-разному (или совсем не...), но дело в том, что вы получаете "нежелательные" и "непредсказуемые" результаты.
Теперь представьте, что метод получает "блокировку" переменной, прежде чем пытаться прочитать или записать в нее. Первый поток для вызова метода получит "блокировку" для переменной, второй поток для вызова метода должен будет ждать, пока блокировка не будет освобождена первым потоком. Хотя у вас все еще есть условие гонки (т.е. Второй поток может переписать значение из первого), по крайней мере, у вас есть предсказуемые результаты, потому что ни один из двух потоков (которые не знают друг о друге) может одновременно изменить значение.
Вы используете оператор lock
для получения этой блокировки для переменной. Обычно вы определяете отдельную переменную объекта и используете ее для объекта блокировки:
public class MyThreadSafeClass
{
private readonly object lockObject = new object();
private string mySharedString;
public void ThreadSafeMethod(string newValue)
{
lock (lockObject)
{
// Once one thread has got inside this lock statement, any others will have to wait outside for their turn...
mySharedString = newValue;
}
}
}
Тип считается "потокобезопасным", если он применяет принцип отсутствия коррупции, если доступ к общим данным осуществляется несколькими потоками одновременно.
Остерегайтесь разницы между "неизменяемыми" и "потокобезопасными". Thread-safe говорит, что вы закодированы для сценария и не получите коррупцию, если два потока обращаются к общему состоянию в одно и то же время, в то время как неизменность просто говорит, что вы возвращаете новый объект, а не изменяете его. Неизменяемые объекты являются потокобезопасными, но не все поточно-безопасные объекты неизменяемы.
Потоковый безопасный код означает код, к которому можно получить доступ со многими потоками и по-прежнему работать правильно.
В С# это обычно требует своего рода механизма синхронизации. Простым является оператор lock
(который за кулисами вызывает вызов Monitor.Enter
). Кодовый блок, окруженный блоком lock
, может быть доступен только по одному потоку за раз.
Любое использование типа, не являющегося потокобезопасным, требует, чтобы вы сами управляли синхронизацией.
Хороший ресурс, чтобы узнать о потоке в С#, - это бесплатная книга Джо Альбахари, найденная здесь.