繁体   English   中英

C#线程和同步

[英]C# threading and synchronization

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

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可以让任何其他线程获取锁定另一个函数中已经锁定的对象吗?

一次只有一个线程可以获取锁,因此该状态对于单个锁实例上的所有线程都是独占的。 因此,在您的示例中,由于您的锁是静态的,因此在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();

我相信你正确阅读MSDN上的锁定声明

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

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

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

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

首先, _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())
{
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM