ひきぷろのプログラミング日記

プログラミングの日記です。

(C#) Java と同じ仕組みの synchronized メソッドを作成する

C# では synchronized メソッドは作成できない、またはメソッド内で lock キーワードを代わりに使う というような解説記事ばかりが見つかるので、本当にそうなのか?と思って検索してみました。
結果からいうと、作成できるようです。

C# の場合は言語のキーワードとして synchronized が用意されているわけではなく、アノテーションを使ってメソッドの属性を変えてしまう というような仕組みを使うらしいです。

次のようなコードでテストしてみました。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;

class SynchronizedTest {
	private int _value;

	// テスト用のメソッド
	public void Test() {
		long time = Benchmark(() => {
			// スレッド 10 個を作成して、すぐに実行する
			List<Thread> threads = new List<Thread>();
			for (int i = 0; i < 10; i++) {
				Thread thread = new Thread(new ThreadStart(_ThreadMethod));
				thread.Start();
				threads.Add(thread);
			}

			// スレッド 10 個の終了を待つ
			foreach (Thread thread in threads) {
				thread.Join();
			}

			// _value 変数の内容を表示する
			Console.WriteLine("value: {0}", _value);
		}, 1);

		// 実行時間を表示する
		Console.WriteLine("time: {0}", time);
	}

	// 各スレッドで実行するコード
	[MethodImpl(MethodImplOptions.Synchronized)]
	private void _ThreadMethod() {
		for (int i = 0; i < 10000; i++) {
			_value++;
		}
	}

	// 引数で渡したメソッドの実行時間を計る
	private static long Benchmark(Action action, int interval) {
		GC.Collect();
		Stopwatch sw = Stopwatch.StartNew();
		for (int i = 0; i < interval; i++) {
			action.Invoke();
		}
		sw.Stop();
		return sw.ElapsedMilliseconds;
	}
}

_ThreadMethod() の定義部分のすぐ上に書いている MethodImpl アノテーションで (C# 的には Attribute または属性という方が適切かもしれません)、 synchronized の機能を付加しています。

実行すると、

value: 100000

というように表示されます。

試しに MethodImpl をコメントアウトしてみると、 value の値が 100000 以外の値になることがあるので、 MethodImpl で指定した synchronized の機能は効いているようです。