Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当前线程中的单例_C#_Design Patterns - Fatal编程技术网

C# 当前线程中的单例

C# 当前线程中的单例,c#,design-patterns,C#,Design Patterns,我的单身生活如下: public class CurrentSingleton { private static CurrentSingleton uniqueInstance = null; private static object syncRoot = new Object(); private CurrentSingleton() { } public static CurrentSingleton getInstance() {

我的单身生活如下:

public class CurrentSingleton
{
    private static CurrentSingleton uniqueInstance = null;
    private static object syncRoot = new Object();
    private CurrentSingleton() { }

    public static CurrentSingleton getInstance()
    {
        if (uniqueInstance == null)
        {
            lock (syncRoot)
            {
                if (uniqueInstance == null)
                    uniqueInstance = new CurrentSingleton();
            }
        }
        return uniqueInstance;
    }
}
我想检查一下,如果我有两个线程,是否有两个不同的单线程?我想,我将有两个不同的单例(具有不同的引用),因此我正在做的是:

class Program
{
    static void Main(string[] args)
    {
        int currentCounter = 0;
        for (int i = 0; i < 100; i++)
        {
            cs1 = null;
            cs2 = null;

            Thread ct1 = new Thread(cfun1);
            Thread ct2 = new Thread(cfun2);
            ct1.Start();
            ct2.Start(); 
            if (cs1 == cs2) currentCounter++;
        }
        Console.WriteLine(currentCounter);
        Console.Read();

    }

    static CurrentSingleton cs1;
    static CurrentSingleton cs2;

    static void cfun1()
    {
        cs1 = CurrentSingleton.getInstance();
    }

    static void cfun2()
    {
        cs2 = CurrentSingleton.getInstance();
    }
}
类程序
{
静态void Main(字符串[]参数)
{
int currentCounter=0;
对于(int i=0;i<100;i++)
{
cs1=null;
cs2=null;
螺纹ct1=新螺纹(cfun1);
螺纹ct2=新螺纹(cfun2);
ct1.Start();
ct2.Start();
如果(cs1==cs2)currentCounter++;
}
控制台写入线(当前计数器);
Console.Read();
}
静态电流单态cs1;
静态电流单态cs2;
静态无效cfun1()
{
cs1=CurrentSingleton.getInstance();
}
静态无效cfun2()
{
cs2=CurrentSingleton.getInstance();
}
}

我想我应该得到
currentCounter=0
(在这种情况下,每两个单例都是不同的,因为它们是由其他threrad创建的)。不幸的是,例如,我得到了
currentCounter=70
,所以在70种情况下,我有相同的单例。。。您能告诉我为什么吗?

默认情况下,
静态
字段是由访问它的所有线程共享的单个实例

你应该看一下这张照片。将其应用于
静态
字段,使访问它的每个线程都有一个不同的实例

我想检查一下,如果我有两个线程,是否有两个不同的单线程

不,没有。
static
字段在整个
AppDomain
中共享,而不是在每个线程中共享

如果希望每个线程有单独的值,我建议使用来存储备份数据,因为这将为每个线程数据提供一个很好的包装器

另外,在C#中,通常最好通过
lazy
实现一个懒惰的单例,而不是通过双重检查锁定。这看起来像:

public sealed class CurrentSingleton // Seal your singletons if possible
{
    private static Lazy<CurrentSingleton> uniqueInstance = new Lazy<CurrentSingleton>(() => new CurrentSingleton());
    private CurrentSingleton() { }

    public static CurrentSingleton Instance  // use a property, since this is C#...
    {
        get { return uniqueInstance.Value; }
    }
}
public sealed class CurrentSingleton//如果可能,请密封您的单例
{
private static Lazy uniqueInstance=new Lazy(()=>new CurrentSingleton());
私有CurrentSingleton(){}
公共静态CurrentSingleton实例//使用属性,因为这是C#。。。
{
获取{return uniqueInstance.Value;}
}
}
要创建一个为每个线程提供一个实例的类,可以使用:

public sealed class InstancePerThread
{
    private static ThreadLocal<InstancePerThread> instances = new ThreadLocal<InstancePerThread>(() => new InstancePerThread());

    private InstancePerThread() {}
    public static InstancePerThread Instance
    {
        get { return instances.Value; }
    }
}
公共密封类InstancePerThread
{
private static ThreadLocal instances=new ThreadLocal(()=>new InstancePerThread());
私有InstancePerThread(){}
公共静态InstancePerThread实例
{
获取{return instances.Value;}
}
}

使用锁定对象可确保只创建一个值;您可以通过在
CurrentSingleton
构造函数中添加一些日志来验证这一点

然而,我认为在您的逻辑中有一个小缺口:假设两个线程同时调用此方法,而
uniqueInstance
为空。两者都将计算
=null
子句,并前进到锁定。一个将获胜,锁定
syncRoot
,并初始化
uniqueInstance
。当
lock
块结束时,另一个将获得自己的锁,并再次初始化
uniqueInstance


在测试
uniqueInstance
是否为空之前,您需要锁定
syncRoot

无论您做什么,您都永远不会得到currentCounter=0。 因为我们忘记了一个事实,application/C#code也在某个线程中运行,并且C#设置了一些运行代码的优先级。如果您通过在Main方法和CurrentSingleton中放置断点来调试代码,您将注意到这一点。当您到达并为CurrentSingleton创建新对象时,for循环可能是迭代3或4或任何数字。迭代速度很快,代码正在比较空值和对象或对象和空值。我想这就是问题所在

has got point static将始终共享,因此您需要按照以下方式更改代码

  public class CurrentSingleton
  {
    [ThreadStatic]
    private static CurrentSingleton uniqueInstance = null;
    private static object syncRoot = new Object();
    private CurrentSingleton() { }

    public static CurrentSingleton getInstance()
    {
        if (uniqueInstance == null)
            uniqueInstance = new CurrentSingleton();

        return uniqueInstance;
    }
}

根据分析,在第70次迭代中,你们会得到两个不同的对象,但这是不匹配的,可能是null和Object,或者Object和null。要成功创建两个不同的对象,需要使用[ThreadStatic]

我不知道
ThreadLocal
。使用它可能比使用
[ThreadStatic]
@TimothyShields更好是的,它是一个更好的抽象。您可以自己清理,并且初始化要好得多。@Reed Copsey使用您的类I have currentCounter=13或currentCounter=18。所以在某些情况下,我们仍然有相同的例子。。。这不好,不是吗?@makcis这仍然会使用相同的实例。正如我所说的,如果您想避免使用相同的实例,您需要使用
ThreadLocal
[ThreadStatic]
可以工作,但要注意存在一些奇怪的初始化问题(字段初始值设定项只在访问的第一个线程上工作),如果您需要处理实例,则没有干净的方法来处理清理。我补充道[线程静态]在变量static CurrentSingleton cs1;和static CurrentSingleton cs2;之前。现在我得到currentCounter=100,所以在每种情况下我都有相同的实例…它仍然是wrong@makcis您需要在CurrentSingleton类中使用它,而不是您正在设置的变量。在锁中有一个单独的检查,因此它实际上可以在(microsoft CLR的实现)的.NET内存模型。诚然,理论上它需要内存屏障才能正确,但双重检查锁定“基本上”是可以的。使用
[ThreadStatic]时不需要锁定
,因为两个线程不可能在该资源上存在资源争用…我更正了代码。我只是在调试时将我的分析结果放入其中。如果我错了,请更正。您只需