2010-11-02 3 views
5

Я новичок в C#, и я хотел бы спросить, если я эту ситуацию MULTI НИТЕЙ (псевдокод):блокировки на переменную в несколько потоков

public class ClassA 
{ 
    ClassB c = new ClassB(); 
    public void someMethod() 
    { 
      c.myVar = 1; 
      // Some other stuff 
      c.myVar = 0; 
    } 
} 

public class ClassB 
{ 
    private int myVar; 

    public void MethodA() 
    { 
     if(myVar = 1) 
       myVar = 0; 
    } 
} 

Если SomeMethod() и Methoda() может быть активным в отдельных потоках, тогда MethodA() может оценивать оператор if как истинный; но до того, как он установит myVar = 0 someMethod устанавливает myVar = 0, что делает неправильным установить myVar в 0 в MethodA() !!

В принципе, как я могу заблокировать myVar: могу ли я заблокировать {} свойство myVar (установить, получить) или мне нужно использовать Interlock (у меня еще нет опыта Interlock)?

+2

1) Не вызывайте переменную типа ClassB для c, которая запутывает. –

+1

Вы имели в виду 'if (myVar == 1)'? – Vlad

+2

2) Вы не можете получить доступ к c.myVar, поскольку он является частным членом ClassB. –

ответ

1

Вот как я это делаю.

static readonly object _myVar_Lock = new object(); 
    private int _myVar = 0; 

    public int myVar 
    { 
     get { lock (_myVar_Lock) { return this._myVar; } } 
     set { lock (_myVar_Lock) { this._myVar = value; } } 
    } 
+1

Нет, это совершенно бесполезно, чтение и запись этого ._myVar в этом случае является атомарным по спецификации C#. (так как это int). Блокировка необходима для обработки case 'if (myVar == 1) myVar = 0;' без возможности изменения другого потока myVar, чтобы сказать 2 между ними. –

+0

Альбин - пожалуйста, объясните немного, почему это не сработает? – SimpleOne

+0

Альбин, ты ошибаешься. Почему в классе Interlocked существует метод Exchange(), если «myVar = value» является атомарным? Ответ заключается в том, что запись не является атомарной. http://msdn.microsoft.com/en-us/library/d3fxt78a.aspx –

-1

Есть ли причина, по которой у вас есть несколько потоков, которые используют один и тот же экземпляр вашего класса вместо того, чтобы внедрять каждый поток, чтобы он получал свой собственный экземпляр вашего класса в пределах своей области?

3

Похоже, вы пытаетесь реализовать какой-то механизм сигнализации. Вместо того, чтобы писать самостоятельно, вы можете использовать один из классов, предоставляемых в библиотеке .NET, например, ManualResetEvent.

15

Вы должны создать частный объект, который позволит блокировки:

private readonly object _locker = new object(); 

Затем в методах получения/установки свойств, замок вокруг него:

get { lock (_locker) { return this.myVar; } } 
set { lock (_locker) { this.myVar = value; } } 

Убедитесь, что ваш метод использует блокировку также:

public void MethodA() 
{ 
    lock(_locker) 
    { 
     if(myVar == 1) 
      myVar = 0; 
    } 
} 
+0

Нужна ли мне подобная блокировка для набора {}? – SimpleOne

+0

Да, если вам нужен сеттер. Я буду обновлять – aqwert

+0

Как это относится к состоянию гонки в 'someMethod'? –

1

Я бы, конечно, переосмыслил ваш общий подход, но если вы хотите синхронизировать ronize доступ к членам ClassB из разных разделов кода, тогда вы можете украсть не очень хороший шаблон дизайна из интерфейса ICollection и открыть свойство SyncRoot, которое может быть использовано для получения того же замка, что и исходный экземпляр.

public class ClassA 
{ 
    private ClassB c = new ClassB(); 

    public void someMethod() 
    { 
    lock (c.SyncRoot) 
    { 
     c.MyVar = 1; 
     // Some other stuff 
     c.MyVar = 0; 
    } 
    } 
} 

public class ClassB 
{ 
    private object m_LockObject = new object(); 
    private int m_MyVar; 

    public object SyncRoot 
    { 
    get { return m_LockObject; } 
    } 

    public int MyVar 
    { 
    get { lock (SyncRoot) return m_MyVar; } 
    set { lock (SyncRoot) m_MyVar = value; } 
    } 

    public void MethodA() 
    { 
    lock (SyncRoot) 
    { 
     if (m_MyVar == 1) m_Var = 0; 
    } 
    } 
} 
Смежные вопросы