2010-11-02 4 views
11

Здесь я задал вопрос Lock on a variable in multiple threads, поэтому для ясности я собираюсь спросить его здесь и надеюсь, что смогу запросить его правильно.Как заблокировать переменную, используемую в нескольких потоках

classA 
    creates instance of classB 
    has methodA that can update & uses classB's myVar 
    has methodB that can update & uses classB's myVar 

classB 
    has a variable myVar 

методA и methodB могут работать как отдельные потоки (называемые новыми потоками из основного). Как обеспечить безопасность потока?

+2

Основываясь на вашем другом вопросе, вы должны описать ситуацию с более высокого уровня, потому что действительно кажется, что вы идете в неправильном направлении. –

ответ

17

Используйте ключевое слово 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.

0

Ознакомьтесь с документацией к документации lock.

0

ClassB не должен подвергаться воздействию переменной (по которой вы, вероятно, имеете в виду элемент данных). Вместо этого выведите свойство или набор методов и используйте ReaderWriterLockSlim для обработки нескольких потоков.

+0

Рекомендация для этого класса преждевременна, учитывая недостаток информации в вопросах, imo –

+0

Вы можете (и должны) делать свои собственные тесты, но я думаю, вы обнаружите, что 'ReaderWriterLockSlim' будет до 5 раз медленнее обычного старого' блокировка' в этом случае. –

0

Самое простое решение: не используйте экземпляр ClassB среди ваших потоков.

Другими словами, создайте новый ClassB с объявлением потока и отправьте его как параметр.

3

Я написал blog post о том, что несколько потоков добавляют значения в список и используют lock(), чтобы предотвратить столкновение записей и почему это необходимо сделать.

1

К сожалению, вопрос несколько неоднозначен в отношении того, что считается успешным с точки зрения безопасности потоков. Безопасность потока просто означает, что операция будет работать правильно, если выполняются несколько потоков.

Недостаточно то, должен ли классA.methodA или classA.methodB завершить работу с классомB.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 
     } 
    } 
} 
+0

Второй блок кода небезопасен. Чтение 'b.myVar' может происходить одновременно с записью на' b.myVar', если вы попытаетесь выполнить чтение за пределами блокировки. –

Смежные вопросы