« Visual Studio 2005 Beta 2 日本語版 | メイン | 資格取得に自腹で1万5000円は多いか、少ないか »

MonitorクラスとSyncLockキーワードとの比較

MSDN Magazine Febrary 2005の記事を検証してみました。

http://msdn.microsoft.com/msdnmag/issues/05/02/BasicInstincts/default.aspx

といっても、メインのテーマではなくて、まずはMonitorクラスとSyncLockとの類似点(あるいは相違点)の確認。
#言うまでもなく、SyncLockはVisual Basic .NETのキーワード。C#ではlockです。

以下のような簡単なコードを書いてみました。
Pointを表す単純なクラスをMonitorを使う方法とSyncLockを使う方法とで比較するものです。

----------------------------------------------------------------
Imports System.Threading


Public Class PointMonitor
  Private x As Integer
  Private y As Integer

  Sub New(ByVal x As Integer, ByVal y As Integer)
    Me.x = x
    Me.y = y
  End Sub

  Sub GetPointPosition(ByRef x As Integer, ByRef y As Integer)
    Monitor.Enter(Me)
    Try
      x = Me.x
      y = Me.y
    Finally
      Monitor.Exit(Me)
    End Try
  End Sub

  Sub SetPointPosition(ByVal x As Integer, ByVal y As Integer)
    Monitor.Enter(Me)
    Try
      Me.x = x
      Me.y = y
    Finally
      Monitor.Exit(Me)
    End Try
  End Sub
End Class


Public Class PointLock
  Private x As Integer
  Private y As Integer

  Sub New(ByVal x As Integer, ByVal y As Integer)
    Me.x = x
    Me.y = y
  End Sub

  Sub GetPointPosition(ByRef x As Integer, ByRef y As Integer)
    SyncLock Me
      x = Me.x
      y = Me.y
    End SyncLock
  End Sub

  Sub SetPointPosition(ByVal x As Integer, ByVal y As Integer)
    SyncLock Me
      Me.x = x
      Me.y = y
    End SyncLock
  End Sub
End Class
----------------------------------------------------------------

これをビルド(Release Build)して、ディスアセンブラ(Ildasm.exe)を使って、実際にどのようなMSILコードが生成されたのか見てみました。

------ PointMonitorクラスのGetPointPositionメソッド ------
.method public instance void GetPointPosition(int32& x, int32& y) cil managed
{
// コード サイズ 32 (0x20)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call void [mscorlib]System.Threading.Monitor::Enter(object)
.try
{
IL_0006: ldarg.1
IL_0007: ldarg.0
IL_0008: ldfld int32 LockTest.PointMonitor::x
IL_000d: stind.i4
IL_000e: ldarg.2
IL_000f: ldarg.0
IL_0010: ldfld int32 LockTest.PointMonitor::y
IL_0015: stind.i4
IL_0016: leave.s IL_001f
} // end .try
finally
{
IL_0018: ldarg.0
IL_0019: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_001e: endfinally
} // end handler
IL_001f: ret
} // end of method PointMonitor::GetPointPosition
----------------------------------------------------------

------ PointLockクラスのGetPointPositionメソッド ------
.method public instance void GetPointPosition(int32& x, int32& y) cil managed
{
// コード サイズ 34 (0x22)
.maxstack 2
.locals init (class LockTest.PointLock V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: call void [mscorlib]System.Threading.Monitor::Enter(object)
.try
{
IL_0008: ldarg.1
IL_0009: ldarg.0
IL_000a: ldfld int32 LockTest.PointLock::x
IL_000f: stind.i4
IL_0010: ldarg.2
IL_0011: ldarg.0
IL_0012: ldfld int32 LockTest.PointLock::y
IL_0017: stind.i4
IL_0018: leave.s IL_0021
} // end .try
finally
{
IL_001a: ldloc.0
IL_001b: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_0020: endfinally
} // end handler
IL_0021: ret
} // end of method PointLock::GetPointPosition
-------------------------------------------------------

Monitorを使う方がわずかにコードサイズは小さいようですが、ほぼ違いはないと言っていいでしょう。結局SyncLockの方もコンパイルするとMonitor.Enterが使われていますし。

ということでSyncLockはMonitorを使ってロックする方法に対する簡単な記述を提供してくれるものだということがわかるわけです。
TryだのFinallyだの書かなくていいぶん、コードがシンプルで見やすくなりますね。

とすると、Monitor.Enterを使うのは、言語仕様としてSyncLock(やC#のlock)に相当するキーワードを持っていない言語製品の場合に限られると思っていいかもしれません。あとは、コードでSyncLockを使う場合、頭の中でほぼ等価なMonitor.Enterと置き換えてみて、ロジックの確認をしてみるのはいいことでしょうね。

ただし、SyncLockでは足りないこともあって、それはアクセスの競合が発生した場合のタイムアウトが必要な場合。この時はMonitor.TryEnterメソッドを使うことになります。

上記の記事はなかなか興味深い内容になっています。一読をお勧めします。

About

2005年05月04日 23:42に投稿されたエントリーのページです。

ひとつ前の投稿は「Visual Studio 2005 Beta 2 日本語版」です。

次の投稿は「資格取得に自腹で1万5000円は多いか、少ないか」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.34