c#单例对象的多个实例

本文关键字:实例 单例 对象 | 更新日期: 2023-09-27 18:16:53

我对Singleton模式有一个问题。

这真的很奇怪,但看起来我的Singleton模式有两三个实例。我的网站,是一个动作网站,有计时器,我用我的单例对象处理这些计时器和价格。

实际情况是,当他们处于不同的网络中时,有些人总是看到某些价格,而其他人总是看到其他价格。

例如,在我的办公室,我的同事看到一些拍卖价格为0.56美分,每个人都看到相同的,但在另一个网络中,例如,我的房子,我看到0.55美分,计时器也有不同的值。

说到这里,我已经通过生成GUID并将其记录在日志文件中测试了我的Singleton。下面是一些代码

public class Singleton
{
    private static Singleton instance;
    private static System.Threading.Mutex mutex;
    System.Guid token;
    private Singleton() { 
        token = System.Guid.NewGuid();
        Logger.Log("New singleton Instance" + token.toString());
    }
    static Singleton()
    {
        instance = new Singleton();
        mutex = new System.Threading.Mutex();
    }
    public static Singleton Acquire()
    {
        mutex.WaitOne();
        return instance;
    }
    // Each call to Acquire() requires a call to Release()
    public static void Release()
    {
        mutex.ReleaseMutex();
    }
    public void SomeAction()
    {
       Logger.Log(token.toString() + " - SomeAction");
    }
}

在这段代码中,我在构造函数上生成令牌,并记录新Singleton的创建,然后…在SomeAction方法中,我记录谁正在执行该操作。

在此之后,我们做了几个测试并下载了日志文件。

令我惊讶的是,我只看到一个正确的"New Singleton Instance bla"。但是,许多调用SomeAction方法的guid不同,这很奇怪。

我检查了对象只在静态构造函数中创建,并且我还检查了在任何地方都没有手动创建。

更多信息,这只发生在我的生产服务器上,这是一个goDaddy主机。我问过我的网站是否有多个应用程序池,他们说只有一个应用程序池。

c#单例对象的多个实例

您的单例生命周期与IIS的当前工作进程绑定。

如果你配置了多个工作进程,那么不是所有的请求都由同一个进程处理,因此不是同一个单例。

我不能肯定这是你的问题,但它可能值得检查:

  • 如果你在日志框架初始化之前创建了一个实例,消息会被缓存,还是被丢弃?我以前见过日志消息丢失,因为它们发生在日志初始化之前。
  • 是否有可能引用包含此类的程序集的多个版本?这可能导致为每个程序集版本创建一个类实例,因此所看到的值将取决于调用它的代码。然而,这并不能解释从不同地理位置访问相同页面时,您看到的不同值的行为。
  • 如果可以的话,我也想记录某种形式的唯一机器id,以验证在一台机器上运行的代码只有一个副本。当试图理解模糊的行为时,"不相信任何人,证明一切"是一个非常有用的启发式。

您的网站可能只使用一个应用程序池,但是一个应用程序池可能产生多个主机进程。检查应用程序池的工作进程数

问题可能是你实现的单例模式不是线程安全的。因为在一个web应用程序中,你有多个线程同时运行(工作进程),可能会发生两个线程创建两个不同的类实例。你还应该考虑你的web应用运行在哪里。如果你把你的web应用部署在一个web-farm上,可能会发生不同的web服务器在web服务器的内存中获得你的类的不同实例作为静态变量"live"。

似乎您的静态构造函数没有检查是否已经创建了实例。比如:

static Singleton()
    {
    if (instance == null)
        {
        instance = new Singleton();
        mutex = new System.Threading.Mutex();
        }
    }

应该确保类中的其他方法实际上使用的是instance的同一个"实例"