C#线程和同步

时间:2011-01-26 09:25:45

标签: c# multithreading synchronization locking

我有一个私有静态字段,用于同步(锁定)。现在我有两个函数,我不想同时执行。所以我这样做了:

public class Synchronization
{
    private static object _lock = new object();

    public void MethodA()
    {
        lock (_lock)
        {
            Console.WriteLine("I shouldn't execute with MethodB");
        }
    }

    public void MethodB()
    {
        lock (_lock)
        {
            Console.WriteLine("I shouldn't execute with MethodA");
        }
    }
}

我知道锁定一个对象会阻止单个函数的并行执行,但如果我在同时运行的不同方法中使用相同的锁对象,那么同样会有效吗?简单地说,put可以让任何其他线程获取锁定在另一个函数中已经锁定的对象上吗?

5 个答案:

答案 0 :(得分:5)

一次只有一个线程可以获取锁,因此该状态对于单个锁实例上的所有线程都是独占的。因此,在您的示例中,只有一个方法体可能在任何给定时间执行类Synchronization的所有实例,因为您的锁是静态的。如果要锁定每个类的实例,请不要将锁定对象标记为静态。

您对同步的假设是正确的。

请注意,您应该将锁定对象readonly标记为完全防水的解决方案。如代码所示,可以重新分配锁定对象,从而打破锁定语义,例如:

public class Synchronization
{
    private static object _lock = new object();

    public void MethodA()
    {
        lock (_lock)
        {
            Console.WriteLine("I shouldn't execute with MethodB");
        }
    }

    public void MethodB()
    {
        //This shouldn't be allowed!
        _lock = new object();

        lock (_lock)
        {
            Console.WriteLine("I shouldn't execute with MethodA");
        }
    }
}

锁定对象应标记为readonly,即:

private static readonly object _lock = new object();

答案 1 :(得分:2)

我相信你正确阅读MSDN上的Lock Statement

答案 2 :(得分:1)

你正确地做到了。您创建了两个不会同时输入的关键部分。

因此,MethodA和MethodB不会同时处于“活动状态”。此外,只有一个MethodA(和MethodB)同时处于活动状态。

这适用于您创建的所有对象。我的意思是:任何MethodA或MethodB中只有一个线程来自任何对象。如果希望锁仅在一个对象中发生,则可以使_lock对象不是静态的。

答案 3 :(得分:1)

根据作为锁定目标的对象授予锁定,而不是发生lock语句的方法。因此,在您的情况下,多个线程可能会输入各种方法,但一次只有一个线程可以执行lock语句中的任何代码。

答案 4 :(得分:1)

首先,_lock不应该是静态的。或者您希望对象的多个实例彼此锁定自己?其次,您应该在类中只有一个synchronized方法。更重要的是,您应该避免类中同步方法之间的依赖关系。否则,您的方法调用者会冒错误并出现意外行为。

例如,考虑一下这段代码:

class Synchronized
{
    object lockObj = new object();
    int counter = 100;

    public void Decrement()
    {
        lock (this.lockObj)
        {
            this.counter--;
        }
    }

    public int IsZero()
    {
        lock (this.lockObj)
        {
            return this.counter == 0;
        }
    }
}

现在用共享的同步实例做什么?

像这样使用

while (!synchronized.IsZero())
{
    synchronized.Decrement();
}

现在线程1调用Decrement,计数器变为0并且线程2立即调用Decrement,因为它在Decrement方法中等待锁定,而不是IsZero方法。计数器现在为-1,循环是无限的。

并不是锁定机制编程错误,而是调用者没有很好地使用它。如果你只在Synchronized类上暴露了一个同步方法,你就不会愚弄程序员盲目地相信它是安全的。

它应该是这样的:

class Synchronized
{
    object lockObj = new object();
    int counter = 100;

    public bool IfNotZeroDecrement()
    {
        lock (this.lockObj)
        {
            if (this.counter > 0)
                this.counter--;

            return this.counter > 0;
        }
    }    
}

/// Usage:
while (synchronized.IfZeroDecrement())
{
}
相关问题