- PR -

C#のSingletonは静的クラスでlockを省略するのが一般的か

投稿者投稿内容
Tacchang
ベテラン
会議室デビュー日: 2004/09/05
投稿数: 55
お住まい・勤務地: 川崎市
投稿日時: 2005-08-15 23:20
みなさん,こんにちは.
C#でSingletonを作る時のイディオムについて確認させてください.

C#には,C++と異なり静的クラスというのがあるようですが,この静的クラスは「.Net Framework は、static type に対してthread-safe を保障する」Uchukamen C# Programming(宇宙仮面様),ならば,Singletonにする場合は,C++みたいに排他をアプリケーション側(.Net Frameworkが考える)で考える必要が無く,静的クラスにすることでお手軽にSingletonが成立すると思うのですがいかがでしょうか.
ほげた
ベテラン
会議室デビュー日: 2002/05/08
投稿数: 67
お住まい・勤務地: なごやん
投稿日時: 2005-08-16 01:18
言語的に静的クラスがサポートされるのは 2.0 からですね。

C#でのSingletonについては、ここらへんが参考になるかと。
http://www.microsoft.com/japan/msdn/library/ja/dnpatterns/htm/ImpSingletonInCsharp.asp?frame=true

遅延インスタンス化する必要が無ければ、排他制御せずに簡単な実装でOKということです。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2005-08-16 01:38
C#は自分でコードを書いたことすらないので、僭越ながら・・・。

static class(.NET 2.0ですか?)は、クラス内で宣言される全てが
staticであることを強制するためのキーワードのように見えます。

Singletonとは「あるクラスのインスタンスがひとつしかないことを保証する」
パターン(状況によってはあるクラスに互換性のある型のインスタンスかも)なので、
全てがstaticなクラスとSingletonとでは意味が変わってくると思います。

引用:
「.Net Framework は、static type に対してthread-safe を保障する」


もしもstaticなオブジェクトの初期化がThread-Safetyに行われなかった場合、
クラスが初期化されるタイミングをプログラマの責任で同期化する必要が
出てくるので、それを回避するための自然な仕様と言えるでしょう。

この仕様から、

引用:
private static readonly Singleton instance = new Singleton();



このinstanceがSingletonであると保証することができます。

また、C++だとしても、
static const Singleton *const pInstance = new Singleton;
という定数は、アドレスをキャストするして更新するような強引な手段を使う
ことがありえないことを前提とすれば、Singletonと言えるでしょう。

#静的に呼ばれるコンストラクタ内ではSingletonとは限らないかな?

間違っていたら、どなたかツッコミお願いします。
がらす
ベテラン
会議室デビュー日: 2005/07/14
投稿数: 99
投稿日時: 2005-08-16 02:38
C++では、
MyClass& myClassInstance()
{
static MyClass p;
return p;
}

でシングルトンが出来ると思ってました。C#でも同じアプローチで可能だと思っていたのですが…。
cats
大ベテラン
会議室デビュー日: 2002/11/29
投稿数: 221
お住まい・勤務地: 東京
投稿日時: 2005-08-16 10:33
やってみると、スレッドセーフではないようです。
コード:
public class Singleton
{
	int		i;
	private static readonly Singleton ins = new Singleton();
	private Singleton() {i = 0;}
	public static Singleton Instance {get {return ins;}}
	public void UnlockedFunc()
	{
		++i;
		Thread.Sleep(100);
		Console.WriteLine(i);
		--i;
	}
	public void LockedFunc()
	{
		lock (this) UnlockedFunc();
	}
}
class Test
{
	[STAThread]
	static void Main(string[] args)
	{
		Singleton s = Singleton.Instance;
		for (int i=0;i<10;++i)
			new Thread(new ThreadStart(s.UnlockedFunc)).Start();
		Thread.Sleep(200);
		for (int i=0;i<10;++i)
			new Thread(new ThreadStart(s.LockedFunc)).Start();
	}
}

あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2005-08-16 13:47
引用:
MyClass& myClassInstance()
{
static MyClass p;
return p;
}



これでも外部からインスタンスを生成できないようにすれば、
静的なコンストラクタ呼び出し以外からはSingletonになりますよ。

#この場合のコンストラクタ呼び出し順序は未定義だったと思うので。

static Singleton *const pInstance = new Singleton;

これはC#のnewの近い形で書いてみたまでです。先頭のconstは不要でしたね。

引用:
やってみると、スレッドセーフではないようです。



Thread-Safetyであるのは、static領域の初期化に限った話です。
そのクラスのメソッドが同期化される意味ではないですよ。

それに、たとえ全てのメソッドが同期化されたとしても、それだけで
単純にそのクラス全体が真にThread-Safetyであるとは言い切れません。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-08-16 14:14
こういうの をやると、わかってくるかもしれませんね。



_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
Tacchang
ベテラン
会議室デビュー日: 2004/09/05
投稿数: 55
お住まい・勤務地: 川崎市
投稿日時: 2005-08-18 07:37
みなさん,ありがとうございました.
ところで,
報告を忘れていましたが私が使っているのはVisual Studio 2005 のためC#2.0です.
従って,static class OKです.
static classの場合,これまでのように
private static readonly Singleton instance = new Singleton();
は必要ないんですよね.

スキルアップ/キャリアアップ(JOB@IT)