C# 每次将代码段锁定到一个入口

C# 每次将代码段锁定到一个入口,c#,multithreading,synchronization,locking,C#,Multithreading,Synchronization,Locking,我试图限制对单音对象的访问,因此只有一个线程 使用它的时候,而且,我想防止同一线程访问两次 到限制代码 我尝试了锁定方法,发现锁定她的线程不是锁定的,而是其他线程 详情如下: public sealed class Singleton { private static readonly Singleton instance = new Singleton(); static Singleton() { } private Singleton()

我试图限制对单音对象的访问,因此只有一个线程 使用它的时候,而且,我想防止同一线程访问两次 到限制代码

我尝试了锁定方法,发现锁定她的线程不是锁定的,而是其他线程

详情如下:

public sealed class Singleton
{
    private static readonly Singleton instance    = new Singleton();

    static Singleton()
    {
    }

    private Singleton()
    {
    }

    public static Singleton Instance
    { 
        get
        {
            return instance;
        }
    }
}

public class SomeWorker
{
    private readonly Timer _doWorkTimer = new Timer(20);

    public SomeWorker()
    {
        InitiateTimer();
    }

    private void InitiateTimer()
    { 
        _doWorkTimer .Elapsed += DoWorkElapse;
        _doWorkTimer .Enabled = true;
    }

    private void DoWorkElapse(object source, ElapsedEventArgs e)
    { 
        DoSomeWork();
    }

    private void DoSomeWork()
    {
        // I know that lock on string is wrong!
        // Its just for the example only I
        // Its just to make sure all the program is use the same lock..
        lock ("ConnectionLock")
        { 
             Console.WriteLine("Lock");

             var inst = Singletone.Instance;

             // Do Some Work on "inst" ...

             Console.WriteLine("Unlock");
        }
    }
}
例如,控制台中的结果是:

。 .

解锁

锁定

锁定

解锁

。 .

正如我们所看到的,两个锁注释一个接一个地显示

这意味着“DoSomeWork()”被计时器线程访问了两次

有人知道怎么锁吗

还有其他同步方法吗


thanx.

您没有正确锁定(最重要的是,您正在锁定一个字符串,这是一个很大的禁忌)。为了节省时间,请阅读Jon Skeet的文章,并实施其中一种模式以避免头痛。

您没有正确地进行锁定(最重要的是,您正在锁定一个字符串,这是一个很大的禁忌)。为了节省时间,请阅读Jon Skeet的文章,并实现其中一种模式以避免您的头痛。

在您的代码中

public static Singletone Instance()
{
    if (_instance == null)
    {
        lock (_instance)
        {
            if (_instance == null)
            {
                _instance = new Singletone ();
            }
        }
    }
    return _instance;;
}
想想看<代码>如果(\u实例==null)您执行了
锁定(\u实例)
。因此,您可以使用
null
锁定。那一点也不好

在MSDN中,如何使用
lock
的示例如下:

class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}
我想你应该遵循它,并有一个单独的对象使用它作为锁


其次,原语用于区分不同线程对共享资源的访问。如果需要将访问与一个线程分开,只需使用标志。大概是这样的:

bool isBusy = false;
public static void Foo()
{
    if (!isBusy)
    {
        isBusy = true;
        try
        {            
            //do the job
        }
        finally
        {
            isBusy = false;
        }
    }
}
在这里,您应该理解,您只需跳过“由标志锁定”代码。相反,如果您想让线程等待自己,特别是在多线程应用程序中,我想它应该重新设计

public static Singletone Instance()
{
    if (_instance == null)
    {
        lock (_instance)
        {
            if (_instance == null)
            {
                _instance = new Singletone ();
            }
        }
    }
    return _instance;;
}
想想看<代码>如果(\u实例==null)您执行了
锁定(\u实例)
。因此,您可以使用
null
锁定。那一点也不好

在MSDN中,如何使用
lock
的示例如下:

class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}
我想你应该遵循它,并有一个单独的对象使用它作为锁


其次,原语用于区分不同线程对共享资源的访问。如果需要将访问与一个线程分开,只需使用标志。大概是这样的:

bool isBusy = false;
public static void Foo()
{
    if (!isBusy)
    {
        isBusy = true;
        try
        {            
            //do the job
        }
        finally
        {
            isBusy = false;
        }
    }
}

在这里,您应该理解,您只需跳过“由标志锁定”代码。相反,如果您想让线程等待自己,特别是在多线程应用程序中,我想它应该重新设计。

在.NET中实现单例的最简单方法是:

public class Singleton : IDisposable
{
    private readonly static Singleton _instance = new Singleton();
    private readonly static object lockObject = new object();

    static Singleton()
    {
    }

    private Singleton()
    {
        InitiateConnection();
    }

    public static Singleton Instance
    {
        get { return _instance; }
    }

    /// <summary>
    /// Method that accesses the DB.
    /// </summary>
    public void DoWork()
    {
        lock (lockObject)
        {
            //Do Db work here. Only one thread can execute these commands at a time.                
        }
    }        

    ~Singleton()
    {
        //Close the connection to DB.

        //You don't want to make your singleton class implement IDisposable because
        //you don't want to allow a call to Singleton.Instance.Dispose().
    }
}
公共类单例:IDisposable
{
私有只读静态单例_instance=new Singleton();
私有只读静态对象lockObject=新对象();
静态单态()
{
}
私人单身人士()
{
InitiateConnection();
}
公共静态单例实例
{
获取{return\u instance;}
}
/// 
///方法访问数据库。
/// 
公共工作
{
锁定(锁定对象)
{
//在这里做Db工作。一次只有一个线程可以执行这些命令。
}
}        
~Singleton()
{
//关闭与数据库的连接。
//您不想让您的单例类实现IDisposable,因为
//您不希望允许调用Singleton.Instance.Dispose()。
}
}
阅读布赖恩在回答中提出的关于这个问题的精彩文章。上述实现基于本文描述的第四个版本。CLR保证静态字段的构造是线程安全的,因此不需要在那里锁定。但是,如果对象的状态(字段)可以更改,则需要锁定


请注意,有一个
私有只读对象
用于确保
DoWork
方法上的互斥。这样,单个线程可以一次调用
DoWork
。还请注意,由于线程按顺序执行指令,因此同一线程不可能同时调用此方法两次。如果在
DoWork
内部调用另一个最终调用
DoWork
的方法,则可以从单个线程调用此方法两次。我看不出这样做有什么意义,如果这样做了,请注意避免堆栈溢出。您可以按照Konstantin的建议使用一个标志,但我认为您应该重新设计
DoWork
,只做一件事,避免出现类似的情况。

在.NET中实现单例的最简单方法是:

public class Singleton : IDisposable
{
    private readonly static Singleton _instance = new Singleton();
    private readonly static object lockObject = new object();

    static Singleton()
    {
    }

    private Singleton()
    {
        InitiateConnection();
    }

    public static Singleton Instance
    {
        get { return _instance; }
    }

    /// <summary>
    /// Method that accesses the DB.
    /// </summary>
    public void DoWork()
    {
        lock (lockObject)
        {
            //Do Db work here. Only one thread can execute these commands at a time.                
        }
    }        

    ~Singleton()
    {
        //Close the connection to DB.

        //You don't want to make your singleton class implement IDisposable because
        //you don't want to allow a call to Singleton.Instance.Dispose().
    }
}
公共类单例:IDisposable
{
私有只读静态单例_instance=new Singleton();
私有只读静态对象lockObject=新对象();
静态单态()
{
}
私人单身人士()
{
InitiateConnection();
}
公共静态单例实例
{
获取{return\u instance;}
}
/// 
///方法访问数据库。
/// 
公共工作
{
锁定(锁定对象)
{
//在这里做Db工作。一次只有一个线程可以执行这些命令。
}
}        
~Singleton()
{
//关闭与数据库的连接。
//您不想让您的单例类实现IDisposable,因为
//您不希望允许调用Singleton.Instance.Dispose()。
}
}
阅读布赖恩在回答中提出的关于这个问题的精彩文章。上述实现基于本文描述的第四个版本。CLR保证静态字段的构造是线程安全的,因此您不需要