如何锁定多个线程中使用的变量

时间:2010-11-02 21:41:05

标签: c# multithreading locking

我在这里严重问了一个问题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

methodA和methodB都可以在不同的线程中运行(在main的新线程中调用)。我如何确保这是线程安全的?

6 个答案:

答案 0 :(得分:19)

使用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的成员仍然是安全的。

答案 1 :(得分:3)

我写了一个blog post关于让多个线程将值添加到列表中并使用lock()来防止写入冲突以及为什么需要这样做。

答案 2 :(得分:0)

查看lock声明文档。

答案 3 :(得分:0)

ClassB不应该暴露变量(您可能意味着数据成员)。改为展示一个属性或一组方法,并使用ReaderWriterLockSlim来处理多个线程。

答案 4 :(得分:0)

最简单的解决方案:不要在线程中共享ClassB的实例。

换句话说,使用您的线程声明实例化一个新的ClassB并将其作为参数发送。

答案 5 :(得分:0)

不幸的是,这个问题在线程安全性方面被认为是成功的有些含糊不清。线程安全只意味着如果多个线程正在执行,操作将正常工作。

似乎缺少的是classA.methodA或classA.methodB是否需要在调用classA.methodA(...)或classA.methodB(...)的另一个线程之前使用classB.myVar完成其操作。它将确定您需要什么类型的锁定模式。

例如,如果您需要保证读取值,它将如下所示:

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
        }
    }
}