Как заблокировать переменную, используемую в нескольких потоках
Я задал здесь вопрос плохо Заблокировать переменную в нескольких потоках, поэтому для ясности я собираюсь спросить об этом здесь и надеюсь, что смогу запросить ее правильно.
classA
creates instance of classB
has methodA that can update & uses classB myVar
has methodB that can update & uses classB myVar
classB
has a variable myVar
methodA и methodB могут запускаться в отдельных потоках (называемых в новых потоках из основного). Как обеспечить безопасность потока?
Ответы
Ответ 1
Используйте ключевое слово lock
для защиты кода, который может выполняться одновременно несколькими потоками.
public class ClassA
{
private ClassB b = new ClassB();
public void MethodA()
{
lock (b)
{
// Do anything you want with b here.
}
}
public void MethodB()
{
lock (b)
{
// Do anything you want with b here.
}
}
}
Важно отметить, что lock
не защищает и не блокирует экземпляр объекта, используемый в инструкции. Вместо этого объект используется как способ идентификации раздела кода, который должен быть предотвращен, если другой раздел с использованием того же экземпляра объекта уже выполняется. Другими словами, вы можете использовать любой экземпляр объекта, который вам нравится в операторах lock
, и было бы безопасно обращаться к членам ClassB
.
Ответ 2
Я написал сообщение о том, что несколько потоков добавляют значения в список и используют lock(), чтобы предотвратить сбой записи, а также почему это необходимо сделать.
Ответ 3
К сожалению, вопрос несколько неоднозначен в отношении того, что считается успешным с точки зрения безопасности потоков. Безопасность потока просто означает, что операция будет работать правильно, если выполняются несколько потоков.
То, что кажется отсутствующим, заключается в том, должен ли classA.methodA или classA.methodB завершить свою работу с classB.myVar перед другим потоком, вызывающим классA.methodA(...) или classA.methodB(...), Он определит, какой тип блокировки вам понадобится.
Например, если вам нужна гарантия на чтение значения, это будет выглядеть следующим образом:
public class classA
{
private classB b = new classB();
public void methodA()
{
lock (b)
{
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar
}
}
public void methodB()
{
lock (b)
{
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar
}
}
}
В другом примере, если b.myVar - это некоторый тип коллекции, который должен быть синхронизирован как кеш, он выглядит следующим образом:
public class classA
{
private classB b = new classB();
public void methodA()
{
// Read b.myVar for missing collection item
lock (b)
{
// Check for missing collection item again. If not missing, leave lock
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar with new array item
}
}
public void methodB()
{
// Read b.myVar for missing collection item
lock (b)
{
// Check for missing collection item again. If not missing, leave lock
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar with new array item
}
}
}
Ответ 4
Ознакомьтесь с заблокировать документацию.
Ответ 5
ClassB
не должен выставлять переменную (по которой вы, вероятно, имеете в виду элемент данных). Вместо этого выведите свойство или набор методов и используйте ReaderWriterLockSlim для обработки нескольких потоков.
Ответ 6
Самое простое решение: не используйте экземпляр ClassB среди ваших потоков.
Другими словами, создайте новый ClassB с объявлением потока и отправьте его как параметр.