在被调用实例方法中锁定问题

时间:2013-11-30 13:38:31

标签: c# .net multithreading thread-safety locking

我一直在经历albahari线程课程,但是当我自己去实验时,事情没有按计划进行。我不知道为什么以下锁定“_Lock”没有阻止。不知何故,每个SafeLock方法中的锁定也不会阻止其他线程使用其方法。已经有一段时间了,所以任何帮助都会非常感激。

//Here I just call a method 10x
//The method (SL1) then creates a SafeLocks object and runs 3 methods
private void SL1_Btn_Click(object sender, EventArgs e)
{
    SL1(); SL1(); SL1(); SL1(); SL1();
    SL1(); SL1(); SL1(); SL1(); SL1();
}
private void SL1()
{
    console.WriteLine("Thread Enter");
    SafeLocks sl = new SafeLocks();
    ThreadPool.QueueUserWorkItem(o => sl.ShowVars());
    ThreadPool.QueueUserWorkItem(o => sl.SetZero());
    ThreadPool.QueueUserWorkItem(o => sl.ShowVars());
    console.WriteLine("Thread Exit");
}

//Now for the Thread-"Safe" class
    class SafeLocks
{
    //private static int staticVar = 1; 
    private static int staticVar = 1; 
    public int instanceVar = 1;
    private static readonly object _Lock = new object();

    public SafeLocks() //sets both to 100,000
    {
        lock (_Lock)
        {
            while (staticVar < 99999)
            { staticVar++; }
            while (instanceVar < 99999)
            { instanceVar++; }
            staticVar++;
            instanceVar++;
            if (instanceVar != 100000)
            { Console.WriteLine("I1=" + instanceVar.ToString()); }
            if (staticVar != 100000)
            { Console.WriteLine(("S1=" + staticVar.ToString())); }
        }
    }
    public void ShowVars()
    {
        lock (_Lock)
        {
            if (instanceVar != 100000 && instanceVar != 0)
            { Console.WriteLine("I2=" + instanceVar.ToString()); }
            if (staticVar != 100000 && staticVar != 0)
            { Console.WriteLine("S2=" + staticVar.ToString()); }
        }
    }
    public void SetZero()
    {
        lock (_Lock)
        {
            while (staticVar > 0)
            {
                staticVar--;
            }
            while (instanceVar > 0)
            {
                instanceVar--;
            }
            if (instanceVar != 0)
            { Console.WriteLine("I3=" + instanceVar.ToString()); }
            if (staticVar != 0)
            { Console.WriteLine("S3=" + staticVar.ToString()); }
        }
    }
}

}

1 个答案:

答案 0 :(得分:2)

问题来自于构造函数的组合以及构造多个实例或调用SetZero之间没有线程安全的事实。也就是说,您可以在调用SetZero之前创建两个实例。 (编辑:你现在的锁正常运行,因为没有方法可以同时执行,但它们没有做任何事情来保证调用这些方法的 order 你设置的线程最终会在最终调用SetZero之前多次调用对象构造函数。)

首先在你的构造函数中(注意,我消除了instanceVar用法,因为它运行正常):

while (staticVar < 99999)
{ staticVar++; }
staticVar++;

假设 staticVar以小于99999 的值开始,然后再增加一个值以使其成为10000 }。但是,如果 p>

通过执行以下操作可以很容易地证明这一点,而无需任何线程:

100000

如果您将构造函数代码更改为:

100001

代码将“正常”,但它仍然技术上可能有一个错误,因为无法保证在创建下一个实例的构造函数之前调用SafeLocks sl = new SafeLocks(); SafeLocks s2 = new SafeLocks(); //outputs "S1=100001" SafeLocks s3 = new SafeLocks(); //outputs "S1=100002" SafeLocks s4 = new SafeLocks(); //outputs "S1=100003" SafeLocks s5 = new SafeLocks(); //outputs "S1=100004" 。我不确定这是否是一个问题,因为这是一个非常人为的设计/示例,但在未来的使用中你需要注意的事情。 (另外,考虑在可能的情况下分离静态和实例级别的线程安全问题)否则,唯一的方法是避免它,即确保在构造另一个之前调用lock (_Lock) { while (staticVar <= 99999) //note the <= comparison change { staticVar++; } while (instanceVar <= 99999) //note the <= comparison change { instanceVar++; } if (instanceVar != 100000) { Console.WriteLine("I1=" + instanceVar.ToString()); } if (staticVar != 100000) { Console.WriteLine(("S1=" + staticVar.ToString())); } } 我相信,在您当前的设计中是非平凡的无论如何,一般来说都很尴尬/不明显。