简单快速的单身模式为你。 [英] Simple and fast Singleton pattern for ya.

查看:59
本文介绍了简单快速的单身模式为你。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅供参考。

///< summary>

///作者:William Stacey

///快速简单的方法实现单例模式而不必诉诸于嵌套类或其他静态vodo
///。也可以很容易地转换为

///允许n要创建的实例数。

///< / summary>

公共类SingletonClass

{

//单例逻辑使用的变量。

private static int created = 0; //还没有创建对象。

private static SingletonClass singletonInstance = null;

//结束单例变量。


//课堂上需要的其他私人/公共变体。

私人字符串名称;


public SingletonClass()

{

name =" MyName";

Console.WriteLine(" Created MyName。");

//其他东西......

}


///< summary>

///返回SingletonClass的单​​个实例(如果存在)。否则

///创建它,存储引用并返回单例。

///这使用非常快速的Interlocked方法,通过CPU完成其工作

///以原子方式说明。几乎和if一样快测试,而

///是线程安全的,不需要内核模式切换或其他

锁定。

///< / summary> ;

///< returns>单例对象。< / returns>

public static SingletonClass GetInstance()

{

if(Interlocked.Exchange(ref created,1)== 1)

return singletonInstance;

singletonInstance = new SingletonClass();

返回singletonInstance;

}


///< summary>

///重置"创建"为零。下一次调用GetInstance()将创建

///一个新的SingletonClass obj。可以用来刷新每天或每个其他事件创建

///一个新对象。这个方法是线程

安全。

///< / summary>

public static void ResetSingleton()

{

Interlocked.Exchange(ref created,0);

}


公共字符串名称

{

get {return this.name; }

}

}


-

William Stacey,MVP

解决方案

William Stacey< st *********** @ mvps.org>写道:

仅供参考。
///< summary>
///作者:William Stacey
///实现单例模式的快速简单方法没有诉诸
///嵌套类或其他静态vodo。也可以很容易地转换为
///允许n要创建的实例数。
///< / summary>




这不是线程安全的。有两个主要问题:


1)如果在另一个GetInstance调用之后调用

GetInstance,则线程最终可能返回null值设置

" created"标志但实际上还没有创建实例。


2)线程最终可能会引用单例,然后才能完成构建 - b
赋值可以是

重新排列到实际构造函数的内容之前。你没有
有任何内存障碍,所以没有保证订购

读写。


-

Jon Skeet - < sk *** @ pobox.com>
http://www.pobox.com/~skeet

如果回复小组,请不要给我发邮件


感谢您看到Jon。那里有一个小窗口。这是修正这种可能性的

修复。

我们使用一次锁定,在多线程实际上试图获得的情况下

在相同的第一个实例时间。

获得锁定的第一个线程将创建实例。如果多个

线程在创建实例之前同时等待锁定,则它们将唤醒。最后看到实例已创建并返回它。任何

未来的线程都不会锁定,但只需快速确定

interlocked.compareexchange来测试创建的。因此,除了第一次使用时注意到的

异常外,没有任何昂贵的锁定。干杯!


///< summary>

///快速而简单的方法来实现单例模式而无需诉诸

///嵌套类或其他静态vodo。也可以很容易地转换为

///允许n要创建的实例数。

///< / summary>

公共类SingletonClass

{

//单例逻辑使用的变量。

private static int created = 0; //还没有创建对象。

private static SingletonClass singletonInstance = null;

//我们的私有锁对象。我们可以使用typeof(SingletonClass)

代替。

私有静态对象syncLock = new object();

//结束单例变量。


//课堂上需要的其他私人/公共变种。

私人字符串名称;


public SingletonClass ()

{

name =" MyName" ;;

Console.WriteLine(" Created MyName。");

}


///< summary>

///返回SingletonClass的单​​个实例(如果存在)。否则

///创建它,存储引用并返回单例。

///这使用非常快速的Interlocked方法,通过CPU完成其工作

///以原子方式说明。几乎和if一样快测试,而

///是线程安全的,不需要内核模式切换或其他

锁定。

///< / summary> ;

///< returns>单例对象。< / returns>

public static SingletonClass GetInstance()

{

//如果已经创建了实例,则创建 var将为1,所以返回

实例。

if(Interlocked.CompareExchange(ref created,1,1)== 1)

返回singletonInstance;


//尚未创建Singleton,获取锁定以原子方式创建

//实例。我们只会在第一次使用/创建时产生锁定罚款。在那之后,我们不会在上面的测试中点击这个锁并只依赖

//来查看是否创建了实例。

lock(syncLock)

{

//如果两个或更多线程碰巧同时等待锁定

//(即线程在启动时放牧)。检查再次作为

的第一个线程获得锁定

//本来已经创建了单例。在不太可能的情况下

线程发生

//在三个线路之间死亡或中止之前设置创建

到1,这仍然有效

//只要锁定即可给另一个等待线程锁定 - 这是

的确如此。

如果(创建== 1)

返回singletonInstance;


// Singleton还没有创建,所以创建它并使用InterlockedExchange设置创建的标志

//。在Singleton创建之前不设置标记和

引用var set。

singletonInstance = new SingletonClass();

Interlocked.Exchange(ref created,1 );

}

返回singletonInstance;

}


公共字符串名称

{

get {return this.name; }

}

}


William Stacey< st *********** @ mvps.org>写道:

感谢您看到Jon。那里有一个小窗口。以下是修正这种可能性的修复方法。
我们使用一次锁定,在多线程实际上试图获得相同的第一个实例的情况下。时间。
第一个获取锁定的线程,将创建实例。如果多个
线程碰巧在创建实例之前同时等待锁定,则它们将唤醒。最后看到实例已创建并返回它。任何
未来的线程都不会锁定,但只需快速
interlocked.compareexchange来测试创建的。因此,除了第一次使用时提到的
异常外,不会遇到昂贵的锁。干杯!




不,你有同样的问题,正常的双重检查锁

算法 - 你可以看到在它被正确初始化之前参考单身。


你基本上需要一个内存障碍*某处*。

-

Jon Skeet - < sk *** @ pobox.com>
http://www.pobox.com/~skeet

如果回复该群组,请不要给我发邮件。 />


FYI.
/// <summary>
/// Author: William Stacey
/// Fast and simple way to implement a singleton pattern without resorting
/// to nested classes or other static vodo. Can also be easily converted to
/// allow "n" number of instances to be created.
/// </summary>
public class SingletonClass
{
// Vars used by singleton logic.
private static int created = 0; // No object created yet.
private static SingletonClass singletonInstance = null;
// End singleton vars.

// Other private/public vars as needed in class.
private string name;

public SingletonClass()
{
name = "MyName";
Console.WriteLine("Created MyName.");
//other stuff...
}

/// <summary>
/// Returns single instance of SingletonClass if it exists. Otherwise
/// create it, store the reference and return the singleton.
/// This uses very fast Interlocked method that does its work via CPU
/// instructions in an atomic way. Almost as fast as an "if" test, while
/// being thread safe and not requiring kernel mode switch or other
locking.
/// </summary>
/// <returns>The singleton object.</returns>
public static SingletonClass GetInstance()
{
if ( Interlocked.Exchange(ref created, 1) == 1 )
return singletonInstance;
singletonInstance = new SingletonClass();
return singletonInstance;
}

/// <summary>
/// Reset "created" to zero. Next call to GetInstance() will create
/// a new SingletonClass obj. Can be used as to "refresh" and create
/// a new object daily or per some other event. This method is thread
safe.
/// </summary>
public static void ResetSingleton()
{
Interlocked.Exchange(ref created, 0);
}

public string Name
{
get { return this.name; }
}
}

--
William Stacey, MVP

解决方案

William Stacey <st***********@mvps.org> wrote:

FYI.
/// <summary>
/// Author: William Stacey
/// Fast and simple way to implement a singleton pattern without resorting
/// to nested classes or other static vodo. Can also be easily converted to
/// allow "n" number of instances to be created.
/// </summary>



That''s not threadsafe. There are two main problems:

1) Threads could end up with a return value of null if they call
GetInstance just after another call to GetInstance which has set the
"created" flag but not actually created the instance yet.

2) Threads could end up with a reference to the singleton before it has
finished being constructed - the reference assignment could be
rearranged to before the content of the actual constructor. You don''t
have any memory barriers, so there''s no guaranteed ordering of the
reads and writes.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


Thanks for seeing that Jon. There was a small window there. Here is the
fix to correct for that possibility.
We use a lock once, in the case where multiple threads actually try to get
the first instance at the "same" time.
The first thread to get the lock, will create the instance. If multiple
threads happen to wait on the lock at same time before the instance is
created, they will "wake" up to see instance was created and return it. Any
future threads will not hit the lock, but just do the quick
interlocked.compareexchange to test for created. So except for the noted
exception on first use, no expensive locks are hit. Cheers!

/// <summary>
/// Fast and simple way to implement a singleton pattern without resorting
/// to nested classes or other static vodo. Can also be easily converted to
/// allow "n" number of instances to be created.
/// </summary>
public class SingletonClass
{
// Vars used by singleton logic.
private static int created = 0; // No object created yet.
private static SingletonClass singletonInstance = null;
//Our private lock object. We could have used typeof(SingletonClass)
instead.
private static object syncLock = new object();
// End singleton vars.

// Other private/public vars as needed in class.
private string name;

public SingletonClass()
{
name = "MyName";
Console.WriteLine("Created MyName.");
}

/// <summary>
/// Returns single instance of SingletonClass if it exists. Otherwise
/// create it, store the reference and return the singleton.
/// This uses very fast Interlocked method that does its work via CPU
/// instructions in an atomic way. Almost as fast as an "if" test, while
/// being thread safe and not requiring kernel mode switch or other
locking.
/// </summary>
/// <returns>The singleton object.</returns>
public static SingletonClass GetInstance()
{
// If instance already created, "created" var will be 1, so return
instance.
if ( Interlocked.CompareExchange(ref created, 1, 1) == 1 )
return singletonInstance;

// Singleton not created yet, get the lock to create
// the instance atomically. We only incur lock penalty on first
// use/creation. After that, we don''t hit this lock and rely only
// on the test above to see if instance created.
lock(syncLock)
{
// If two, or more, threads happen to be wait on lock at same time
// (i.e. threads herding at startup. ) check again as the first thread to
get the lock
// would have already created the singleton. In the unlikely event that
the thread happened
// to die or be aborted between the three lines before it sets "created"
to 1, this still works
// as long as "lock" gives the lock to another waiting thread - which is
does.
if ( created == 1 )
return singletonInstance;

//Singleton not create yet, so create it and set the created flag
//using InterlockedExchange. Flag not set until Singleton created and
reference var set.
singletonInstance = new SingletonClass();
Interlocked.Exchange(ref created, 1);
}
return singletonInstance;
}

public string Name
{
get { return this.name; }
}
}


William Stacey <st***********@mvps.org> wrote:

Thanks for seeing that Jon. There was a small window there. Here is the
fix to correct for that possibility.
We use a lock once, in the case where multiple threads actually try to get
the first instance at the "same" time.
The first thread to get the lock, will create the instance. If multiple
threads happen to wait on the lock at same time before the instance is
created, they will "wake" up to see instance was created and return it. Any
future threads will not hit the lock, but just do the quick
interlocked.compareexchange to test for created. So except for the noted
exception on first use, no expensive locks are hit. Cheers!



Nope, you''ve then got the same problem as the normal double-check lock
algorithm - you could see the reference to the singleton before it''s
properly initialised.

You basically need a memory barrier there *somewhere*.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


这篇关于简单快速的单身模式为你。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆