DoboWiki
Top
> .NETプログラミング研究/26 をテンプレートにして作成
.NETプログラミング研究/26 をテンプレートにして作成
開始行:
#title(.NETプログラミング研究 第26号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第26号 [#e158a430]
**.NET Tips [#q56b20c3]
**.NETのマルチスレッドプログラミング その8 [#q89251a1]
#column(注意){{
この記事の最新版は「[[.NETのマルチスレッドプログラミング>...
}}
.NETのマルチスレッドプログラミングについて、あれやこれや...
***ReaderWriterLockの使い方 [#qb494362]
ReaderWriterLockは、複数スレッドからの共有リソースへのア...
スレッドが読み込みのためのロック(リーダーロック)を取得...
以下にReaderWriterLockを使用した簡単な例を示します。この...
#code(vbnet){{
'Imports System.Threading
'が宣言されているものとする
'ReaderWriterLockオブジェクトの作成
Private Shared rwl As New ReaderWriterLock
'複数スレッドからアクセスする共通リソース
Private Shared resource As String = "0123456789"
'エントリポイント
Public Shared Sub Main()
'スレッドを作成し、開始する
'作成するスレッドのうち半分は共有リソースから読み取る...
'もう半分は共有リソースに書き込むメソッドを実行する
Dim i As Integer
For i = 0 To 199
If i Mod 2 = 0 Then
Dim t As New Thread( _
New ThreadStart(AddressOf ReadFromResourc...
t.Start()
Else
Dim t As New Thread( _
New ThreadStart(AddressOf WriteToResource))
t.Start()
End If
Next i
Console.ReadLine()
End Sub
'共有リソースから読み込む
Private Shared Sub ReadFromResource()
'リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite)
'共有リソースからの読み込みがスレッドセーフ
Console.WriteLine(resource)
'ロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseReaderLock()
End Sub
'共有リソースに書き込む
Private Shared Sub WriteToResource()
'ライタロックを取得
rwl.AcquireWriterLock(Timeout.Infinite)
'共有リソースへの書き込み(読み込みも)がスレッドセーフ
Dim s As String = resource.Substring(0, 1)
resource = resource.Substring(1)
Thread.Sleep(1)
resource += s
'ライタロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseWriterLock()
End Sub
}}
#code(csharp){{
//using System.Threading;
//が宣言されているものとする
//ReaderWriterLockオブジェクトの作成
private static ReaderWriterLock rwl = new ReaderWriterLoc...
//複数スレッドからアクセスする共通リソース
private static string resource = "0123456789";
//エントリポイント
public static void Main()
{
//スレッドを作成し、開始する
//作成するスレッドのうち半分は共有リソースから読み取...
//もう半分は共有リソースに書き込むメソッドを実行する
for (int i = 0; i < 200; i++)
{
if (i % 2 == 0)
{
(new Thread(new ThreadStart(ReadFromResource)...
}
else
{
(new Thread(new ThreadStart(WriteToResource))...
}
}
Console.ReadLine();
}
//共有リソースから読み込む
private static void ReadFromResource()
{
//リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite);
//共有リソースからの読み込みがスレッドセーフ
Console.WriteLine(resource);
//ロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseReaderLock();
}
//共有リソースに書き込む
private static void WriteToResource()
{
//ライタロックを取得
rwl.AcquireWriterLock(Timeout.Infinite);
//共有リソースへの書き込み(読み込みも)がスレッドセ...
string s = resource.Substring(0, 1);
resource = resource.Substring(1);
Thread.Sleep(1);
resource += s;
//ライタロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseWriterLock();
}
}}
リーダーロックを取得中に共有リソースへ書き込む必要が生じ...
ReaderWriterLock.ReleaseLockメソッドでもロックを解放でき...
さらに、WriterSeqNumプロパティで現在のライタシーケンス番...
次にUpgradeToWriterLock、DowngradeFromWriterLockメソッド...
#code(vbnet){{
'Imports System.Threading
'が宣言されているものとする
'ReaderWriterLockオブジェクトの作成
Private Shared rwl As New ReaderWriterLock
'複数スレッドからアクセスする共通リソース
Private Shared resource As String = "0123456789"
'エントリポイント
Public Shared Sub Main()
'スレッドを作成し、開始する
Dim i As Integer
For i = 0 To 199
If i Mod 2 = 0 Then
Dim t As New Thread( _
New ThreadStart(AddressOf UpAndDownGrade))
t.Start()
Else
Dim t As New Thread( _
New ThreadStart(AddressOf ReleaseAndResto...
t.Start()
End If
Next i
Console.ReadLine()
End Sub
'共有リソースを読み書きする
Private Shared Sub UpAndDownGrade()
'リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite)
'共有リソースからの読み取りがスレッドセーフ
Console.WriteLine(resource)
'ライタロックにアップグレード
Dim lc As LockCookie = rwl.UpgradeToWriterLock(Timeou...
'共有リソースへの書き込み(読み込みも)がスレッドセーフ
Dim s As String = resource.Substring(0, 1)
resource = resource.Substring(1)
Thread.Sleep(1)
resource += s
'リーダーロックに戻す
rwl.DowngradeFromWriterLock(lc)
'ロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseReaderLock()
End Sub
'ロックを解放し、復元する
Private Shared Sub ReleaseAndRestore()
'リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite)
'共有リソースからの読み取りがスレッドセーフ
'共有リソースの内容を読み取る
Dim resourceValue As String = resource
'現在のライタシーケンス番号を覚えておく
Dim seqNum As Integer = rwl.WriterSeqNum
'ロックを解放する
'後で復元するため、LockCookieを記憶しておく
Dim lc As LockCookie = rwl.ReleaseLock()
'ロックが解放されている
'ちょっと間を空ける
Thread.Sleep(10)
'ロックを復元する
rwl.RestoreLock(lc)
'ロック開放中に他のスレッドがライタロックを取得したか...
'trueならば共有リソースが変更されたとみなす
If rwl.AnyWritersSince(seqNum) Then
Console.WriteLine("({0})", resourceValue)
'共有リソースから読み込む
resourceValue = resource
End If
'表示する
Console.WriteLine(resourceValue)
'ロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseReaderLock()
End Sub
}}
#code(csharp){{
//using System.Threading;
//が宣言されているものとする
//ReaderWriterLockオブジェクトの作成
private static ReaderWriterLock rwl = new ReaderWriterLoc...
//複数スレッドからアクセスする共通リソース
private static string resource = "0123456789";
//エントリポイント
public static void Main()
{
//スレッドを作成し、開始する
for (int i = 0; i < 200; i++)
{
if (i % 2 == 0)
{
(new Thread(new ThreadStart(UpAndDownGrade)))...
}
else
{
(new Thread(new ThreadStart(ReleaseAndRestore...
}
}
Console.ReadLine();
}
//共有リソースを読み書きする
private static void UpAndDownGrade()
{
//リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite);
//共有リソースからの読み取りがスレッドセーフ
Console.WriteLine(resource);
//ライタロックにアップグレード
LockCookie lc = rwl.UpgradeToWriterLock(Timeout.Infin...
//共有リソースへの書き込み(読み込みも)がスレッドセ...
string s = resource.Substring(0, 1);
resource = resource.Substring(1);
Thread.Sleep(1);
resource += s;
//リーダーロックに戻す
rwl.DowngradeFromWriterLock(ref lc);
//ロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseReaderLock();
}
//ロックを解放し、復元する
private static void ReleaseAndRestore()
{
//リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite);
//共有リソースからの読み取りがスレッドセーフ
//共有リソースの内容を読み取る
string resourceValue = resource;
//現在のライタシーケンス番号を覚えておく
int seqNum = rwl.WriterSeqNum;
//ロックを解放する
//後で復元するため、LockCookieを記憶しておく
LockCookie lc = rwl.ReleaseLock();
//ロックが解放されている
//ちょっと間を空ける
Thread.Sleep(10);
//ロックを復元する
rwl.RestoreLock(ref lc);
//ロック開放中に他のスレッドがライタロックを取得した...
//trueならば共有リソースが変更されたとみなす
if (rwl.AnyWritersSince(seqNum))
{
Console.WriteLine("({0})", resourceValue);
//共有リソースから読み込む
resourceValue = resource;
}
//表示する
Console.WriteLine(resourceValue);
//ロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseReaderLock();
}
}}
***スレッドタイマの使い方 [#vbda9b77]
.NET Frameworkで用意されているタイマには、System.Windows....
サーバータイマについてはヘルプによると、「サーバー ベース...
スレッドタイマは、システムが提供するスレッドプールを使用...
-[[サーバー ベースのタイマの概説>http://www.microsoft.com...
スレッドタイマThreading.Timerを作成するには、コンストラク...
下のコードでは、TimerState.Tickメソッドをスレッドタイマに...
#code(vbnet){{
'Imports System.Threading
'が宣言されているものとする
'マルチスレッドメソッドのためのクラス
'using System.Threading;
'が宣言されているものとする
Class TimerState
Private Count As Integer = 0
Public ThreadTimer As System.Threading.Timer
Public Sub Tick(ByVal state As Object)
'状態オブジェクトの取得
Dim ts As TimerState = CType(state, TimerState)
'カウンタをインクリメント
Count += 1
'表示
Console.WriteLine("システム起動後の経過時間:{0}ミ...
System.Environment.TickCount, Count)
If Count = 5 Then
'5回呼び出されたとき、0.5秒おきに実行されるよ...
ts.ThreadTimer.Change(500, 500)
Console.WriteLine("Changed")
Else
If Count = 10 Then
'10回呼び出されたときは、タイマを破棄する
ts.ThreadTimer.Dispose()
ts.ThreadTimer = Nothing
Console.WriteLine("Disposed")
End If
End If
End Sub
End Class
Class MainClass
'エントリポイント
Public Shared Sub Main()
Dim ts As New TimerState
'Threading.Timerオブジェクトの作成
'TimerState.Tickを0.1秒後に1秒間隔で実行する
ts.ThreadTimer = New System.Threading.Timer( _
New TimerCallback(AddressOf ts.Tick), ts, 100...
'待機する
Console.ReadLine()
End Sub
End Class
}}
#code(csharp){{
//using System.Threading;
//が宣言されているものとする
class TimerState
{
private int Count = 0;
public System.Threading.Timer ThreadTimer;
public void Tick(object state)
{
//状態オブジェクトの取得
TimerState ts = (TimerState) state;
//カウンタをインクリメント
Count++;
//表示
Console.WriteLine("システム起動後の経過時間:{0}ミ...
System.Environment.TickCount, Count);
if (Count == 5)
{
//5回呼び出されたとき、0.5秒おきに実行される...
ts.ThreadTimer.Change(500, 500);
Console.WriteLine("Changed");
}
else if (Count == 10)
{
//10回呼び出されたときは、タイマを破棄する
ts.ThreadTimer.Dispose();
ts.ThreadTimer = null;
Console.WriteLine("Disposed");
}
}
}
class MainClass
{
//エントリポイント
public static void Main()
{
TimerState ts = new TimerState();
//Threading.Timerオブジェクトの作成
//TimerState.Tickを0.1秒後に1秒間隔で実行する
ts.ThreadTimer =
new System.Threading.Timer(
new TimerCallback(ts.Tick), ts, 100, 1000);
//待機する
Console.ReadLine();
}
}
}}
上記コードの結果は例えば次のようになります。
#pre{{
システム起動後の経過時間:8315236ミリ秒(1)
システム起動後の経過時間:8316218ミリ秒(2)
システム起動後の経過時間:8317219ミリ秒(3)
システム起動後の経過時間:8318220ミリ秒(4)
システム起動後の経過時間:8319222ミリ秒(5)
Changed
システム起動後の経過時間:8319723ミリ秒(6)
システム起動後の経過時間:8320223ミリ秒(7)
システム起動後の経過時間:8320724ミリ秒(8)
システム起動後の経過時間:8321225ミリ秒(9)
システム起動後の経過時間:8321726ミリ秒(10)
Disposed
}}
参考:
-[[タイマ>http://www.microsoft.com/japan/msdn/library/ja/...
-[[スレッド タイマ>http://www.microsoft.com/japan/msdn/li...
-[[Timer クラス>http://www.microsoft.com/japan/msdn/libra...
***スレッドセーフなコレクションを使う [#c1a159cd]
System.Collections名前空間にあるコレクションクラス(Array...
コレクションをスレッドセーフにするためには、コレクション...
次にSynchronizedメソッドを使用した例を示します。
#code(vbnet){{
'using System.Collections;
'が宣言されているものとする
'同期されていないArrayListオブジェクトの作成
Dim al As New ArrayList
'alを同期するArrayListラッパーの取得
Dim syncdAl As ArrayList = ArrayList.Synchronized(al)
'同期されたArrayListオブジェクトの作成
Dim syncdAl2 As ArrayList = _
ArrayList.Synchronized(New ArrayList)
'同期されているか確かめる
Console.WriteLine("al.IsSynchronized = {0}", _
al.IsSynchronized)
Console.WriteLine("syncdAl.IsSynchronized = {0}", _
syncdAl.IsSynchronized)
Console.WriteLine("syncdAl2.IsSynchronized = {0}", _
syncdAl2.IsSynchronized)
}}
#code(csharp){{
//using System.Collections;
//が宣言されているものとする
//同期されていないArrayListオブジェクトの作成
ArrayList al = new ArrayList();
//alを同期するArrayListラッパーの取得
ArrayList syncdAl = ArrayList.Synchronized(al);
//同期されたArrayListオブジェクトの作成
ArrayList syncdAl2 = ArrayList.Synchronized(new ArrayList...
//同期されているか確かめる
Console.WriteLine("al.IsSynchronized = {0}",
al.IsSynchronized);
Console.WriteLine("syncdAl.IsSynchronized = {0}",
syncdAl.IsSynchronized);
Console.WriteLine("syncdAl2.IsSynchronized = {0}",
syncdAl2.IsSynchronized);
}}
#pre{{
出力結果;
al.IsSynchronized = False
syncdAl.IsSynchronized = True
syncdAl2.IsSynchronized = True
}}
コレクションの列挙はスレッドセーフな処理ではありませんの...
lockでコレクションをロックする時は、そのコレクション自身...
次にコレクションの列挙処理をスレッドセーフに行う例を示し...
#code(vbnet){{
'using System.Collections;
'が宣言されているものとする
'同期されたArrayList
Private Shared syncdAl As ArrayList = _
ArrayList.Synchronized(New ArrayList)
'エントリポイント
Public Shared Sub Main()
Dim i As Integer
For i = 0 To 99
syncdAl.Add(i)
Next i
'スレッドの作成と開始
Dim t As New Thread(New ThreadStart(AddressOf MyThrea...
t.Start()
'ちょっと待ってから、syncdAlを変更する
Thread.Sleep(500)
syncdAl.RemoveAt(0)
Console.ReadLine()
End Sub
Private Shared Sub MyThread()
'syncdAlをロックする
'これをしないと、例外がスローされる
SyncLock syncdAl.SyncRoot
'列挙処理をする
Dim i As Integer
For Each i In syncdAl
Console.Write(i)
Thread.Sleep(10)
Next i
End SyncLock
End Sub
}}
#code(csharp){{
//using System.Collections;
//が宣言されているものとする
//同期されたArrayList
private static ArrayList syncdAl =
ArrayList.Synchronized(new ArrayList());
//エントリポイント
public static void Main()
{
for (int i = 0; i < 100; i++)
{
syncdAl.Add(i);
}
//スレッドの作成と開始
Thread t = new Thread(new ThreadStart(MyThread));
t.Start();
//ちょっと待ってから、syncdAlを変更する
Thread.Sleep(500);
syncdAl.RemoveAt(0);
Console.ReadLine();
}
private static void MyThread()
{
//syncdAlをロックする
//これをしないと、例外がスローされる
lock(syncdAl.SyncRoot)
{
//列挙処理をする
foreach (int i in syncdAl)
{
Console.Write(i);
Thread.Sleep(10);
}
}
}
}}
ArrayクラスのようにSynchronizedメソッドがないコレクション...
参考:
-[[コレクションと同期 (スレッド セーフ)>http://www.micros...
***Interlockedの使い方 [#b33490fc]
以前「スレッドの同期」にて、「競合状態」の説明をしました...
lockステートメントによる同期により競合状態を防いでインク...
#code(vbnet){{
SyncLock Me
x += 1
End SyncLock
}}
#code(csharp){{
lock (this)
{
x++;
}
}}
実は.NET Frameworkではより優れた方法として、Interlocked.I...
上記のコードをInterlocked.Incrementメソッドで書き直すと、...
#code(vbnet){{
System.Threading.Interlocked.Increment(x)
}}
#code(csharp){{
System.Threading.Interlocked.Increment(x);
}}
Interlockedクラスの4つの静的メソッドIncrement、Decrement...
参考:
-[[Interlocked>http://www.microsoft.com/japan/msdn/librar...
-[[Interlocked クラス>http://www.microsoft.com/japan/msdn...
-[[スレッド処理のデザイン ガイドライン>http://www.microso...
**コメント [#x0ce129e]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2004-02-12 (木) 06:00:00,DOB...
終了行:
#title(.NETプログラミング研究 第26号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第26号 [#e158a430]
**.NET Tips [#q56b20c3]
**.NETのマルチスレッドプログラミング その8 [#q89251a1]
#column(注意){{
この記事の最新版は「[[.NETのマルチスレッドプログラミング>...
}}
.NETのマルチスレッドプログラミングについて、あれやこれや...
***ReaderWriterLockの使い方 [#qb494362]
ReaderWriterLockは、複数スレッドからの共有リソースへのア...
スレッドが読み込みのためのロック(リーダーロック)を取得...
以下にReaderWriterLockを使用した簡単な例を示します。この...
#code(vbnet){{
'Imports System.Threading
'が宣言されているものとする
'ReaderWriterLockオブジェクトの作成
Private Shared rwl As New ReaderWriterLock
'複数スレッドからアクセスする共通リソース
Private Shared resource As String = "0123456789"
'エントリポイント
Public Shared Sub Main()
'スレッドを作成し、開始する
'作成するスレッドのうち半分は共有リソースから読み取る...
'もう半分は共有リソースに書き込むメソッドを実行する
Dim i As Integer
For i = 0 To 199
If i Mod 2 = 0 Then
Dim t As New Thread( _
New ThreadStart(AddressOf ReadFromResourc...
t.Start()
Else
Dim t As New Thread( _
New ThreadStart(AddressOf WriteToResource))
t.Start()
End If
Next i
Console.ReadLine()
End Sub
'共有リソースから読み込む
Private Shared Sub ReadFromResource()
'リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite)
'共有リソースからの読み込みがスレッドセーフ
Console.WriteLine(resource)
'ロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseReaderLock()
End Sub
'共有リソースに書き込む
Private Shared Sub WriteToResource()
'ライタロックを取得
rwl.AcquireWriterLock(Timeout.Infinite)
'共有リソースへの書き込み(読み込みも)がスレッドセーフ
Dim s As String = resource.Substring(0, 1)
resource = resource.Substring(1)
Thread.Sleep(1)
resource += s
'ライタロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseWriterLock()
End Sub
}}
#code(csharp){{
//using System.Threading;
//が宣言されているものとする
//ReaderWriterLockオブジェクトの作成
private static ReaderWriterLock rwl = new ReaderWriterLoc...
//複数スレッドからアクセスする共通リソース
private static string resource = "0123456789";
//エントリポイント
public static void Main()
{
//スレッドを作成し、開始する
//作成するスレッドのうち半分は共有リソースから読み取...
//もう半分は共有リソースに書き込むメソッドを実行する
for (int i = 0; i < 200; i++)
{
if (i % 2 == 0)
{
(new Thread(new ThreadStart(ReadFromResource)...
}
else
{
(new Thread(new ThreadStart(WriteToResource))...
}
}
Console.ReadLine();
}
//共有リソースから読み込む
private static void ReadFromResource()
{
//リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite);
//共有リソースからの読み込みがスレッドセーフ
Console.WriteLine(resource);
//ロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseReaderLock();
}
//共有リソースに書き込む
private static void WriteToResource()
{
//ライタロックを取得
rwl.AcquireWriterLock(Timeout.Infinite);
//共有リソースへの書き込み(読み込みも)がスレッドセ...
string s = resource.Substring(0, 1);
resource = resource.Substring(1);
Thread.Sleep(1);
resource += s;
//ライタロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseWriterLock();
}
}}
リーダーロックを取得中に共有リソースへ書き込む必要が生じ...
ReaderWriterLock.ReleaseLockメソッドでもロックを解放でき...
さらに、WriterSeqNumプロパティで現在のライタシーケンス番...
次にUpgradeToWriterLock、DowngradeFromWriterLockメソッド...
#code(vbnet){{
'Imports System.Threading
'が宣言されているものとする
'ReaderWriterLockオブジェクトの作成
Private Shared rwl As New ReaderWriterLock
'複数スレッドからアクセスする共通リソース
Private Shared resource As String = "0123456789"
'エントリポイント
Public Shared Sub Main()
'スレッドを作成し、開始する
Dim i As Integer
For i = 0 To 199
If i Mod 2 = 0 Then
Dim t As New Thread( _
New ThreadStart(AddressOf UpAndDownGrade))
t.Start()
Else
Dim t As New Thread( _
New ThreadStart(AddressOf ReleaseAndResto...
t.Start()
End If
Next i
Console.ReadLine()
End Sub
'共有リソースを読み書きする
Private Shared Sub UpAndDownGrade()
'リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite)
'共有リソースからの読み取りがスレッドセーフ
Console.WriteLine(resource)
'ライタロックにアップグレード
Dim lc As LockCookie = rwl.UpgradeToWriterLock(Timeou...
'共有リソースへの書き込み(読み込みも)がスレッドセーフ
Dim s As String = resource.Substring(0, 1)
resource = resource.Substring(1)
Thread.Sleep(1)
resource += s
'リーダーロックに戻す
rwl.DowngradeFromWriterLock(lc)
'ロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseReaderLock()
End Sub
'ロックを解放し、復元する
Private Shared Sub ReleaseAndRestore()
'リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite)
'共有リソースからの読み取りがスレッドセーフ
'共有リソースの内容を読み取る
Dim resourceValue As String = resource
'現在のライタシーケンス番号を覚えておく
Dim seqNum As Integer = rwl.WriterSeqNum
'ロックを解放する
'後で復元するため、LockCookieを記憶しておく
Dim lc As LockCookie = rwl.ReleaseLock()
'ロックが解放されている
'ちょっと間を空ける
Thread.Sleep(10)
'ロックを復元する
rwl.RestoreLock(lc)
'ロック開放中に他のスレッドがライタロックを取得したか...
'trueならば共有リソースが変更されたとみなす
If rwl.AnyWritersSince(seqNum) Then
Console.WriteLine("({0})", resourceValue)
'共有リソースから読み込む
resourceValue = resource
End If
'表示する
Console.WriteLine(resourceValue)
'ロックカウントをデクリメント
'0になるとロックが解放される
rwl.ReleaseReaderLock()
End Sub
}}
#code(csharp){{
//using System.Threading;
//が宣言されているものとする
//ReaderWriterLockオブジェクトの作成
private static ReaderWriterLock rwl = new ReaderWriterLoc...
//複数スレッドからアクセスする共通リソース
private static string resource = "0123456789";
//エントリポイント
public static void Main()
{
//スレッドを作成し、開始する
for (int i = 0; i < 200; i++)
{
if (i % 2 == 0)
{
(new Thread(new ThreadStart(UpAndDownGrade)))...
}
else
{
(new Thread(new ThreadStart(ReleaseAndRestore...
}
}
Console.ReadLine();
}
//共有リソースを読み書きする
private static void UpAndDownGrade()
{
//リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite);
//共有リソースからの読み取りがスレッドセーフ
Console.WriteLine(resource);
//ライタロックにアップグレード
LockCookie lc = rwl.UpgradeToWriterLock(Timeout.Infin...
//共有リソースへの書き込み(読み込みも)がスレッドセ...
string s = resource.Substring(0, 1);
resource = resource.Substring(1);
Thread.Sleep(1);
resource += s;
//リーダーロックに戻す
rwl.DowngradeFromWriterLock(ref lc);
//ロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseReaderLock();
}
//ロックを解放し、復元する
private static void ReleaseAndRestore()
{
//リーダーロックを取得
rwl.AcquireReaderLock(Timeout.Infinite);
//共有リソースからの読み取りがスレッドセーフ
//共有リソースの内容を読み取る
string resourceValue = resource;
//現在のライタシーケンス番号を覚えておく
int seqNum = rwl.WriterSeqNum;
//ロックを解放する
//後で復元するため、LockCookieを記憶しておく
LockCookie lc = rwl.ReleaseLock();
//ロックが解放されている
//ちょっと間を空ける
Thread.Sleep(10);
//ロックを復元する
rwl.RestoreLock(ref lc);
//ロック開放中に他のスレッドがライタロックを取得した...
//trueならば共有リソースが変更されたとみなす
if (rwl.AnyWritersSince(seqNum))
{
Console.WriteLine("({0})", resourceValue);
//共有リソースから読み込む
resourceValue = resource;
}
//表示する
Console.WriteLine(resourceValue);
//ロックカウントをデクリメント
//0になるとロックが解放される
rwl.ReleaseReaderLock();
}
}}
***スレッドタイマの使い方 [#vbda9b77]
.NET Frameworkで用意されているタイマには、System.Windows....
サーバータイマについてはヘルプによると、「サーバー ベース...
スレッドタイマは、システムが提供するスレッドプールを使用...
-[[サーバー ベースのタイマの概説>http://www.microsoft.com...
スレッドタイマThreading.Timerを作成するには、コンストラク...
下のコードでは、TimerState.Tickメソッドをスレッドタイマに...
#code(vbnet){{
'Imports System.Threading
'が宣言されているものとする
'マルチスレッドメソッドのためのクラス
'using System.Threading;
'が宣言されているものとする
Class TimerState
Private Count As Integer = 0
Public ThreadTimer As System.Threading.Timer
Public Sub Tick(ByVal state As Object)
'状態オブジェクトの取得
Dim ts As TimerState = CType(state, TimerState)
'カウンタをインクリメント
Count += 1
'表示
Console.WriteLine("システム起動後の経過時間:{0}ミ...
System.Environment.TickCount, Count)
If Count = 5 Then
'5回呼び出されたとき、0.5秒おきに実行されるよ...
ts.ThreadTimer.Change(500, 500)
Console.WriteLine("Changed")
Else
If Count = 10 Then
'10回呼び出されたときは、タイマを破棄する
ts.ThreadTimer.Dispose()
ts.ThreadTimer = Nothing
Console.WriteLine("Disposed")
End If
End If
End Sub
End Class
Class MainClass
'エントリポイント
Public Shared Sub Main()
Dim ts As New TimerState
'Threading.Timerオブジェクトの作成
'TimerState.Tickを0.1秒後に1秒間隔で実行する
ts.ThreadTimer = New System.Threading.Timer( _
New TimerCallback(AddressOf ts.Tick), ts, 100...
'待機する
Console.ReadLine()
End Sub
End Class
}}
#code(csharp){{
//using System.Threading;
//が宣言されているものとする
class TimerState
{
private int Count = 0;
public System.Threading.Timer ThreadTimer;
public void Tick(object state)
{
//状態オブジェクトの取得
TimerState ts = (TimerState) state;
//カウンタをインクリメント
Count++;
//表示
Console.WriteLine("システム起動後の経過時間:{0}ミ...
System.Environment.TickCount, Count);
if (Count == 5)
{
//5回呼び出されたとき、0.5秒おきに実行される...
ts.ThreadTimer.Change(500, 500);
Console.WriteLine("Changed");
}
else if (Count == 10)
{
//10回呼び出されたときは、タイマを破棄する
ts.ThreadTimer.Dispose();
ts.ThreadTimer = null;
Console.WriteLine("Disposed");
}
}
}
class MainClass
{
//エントリポイント
public static void Main()
{
TimerState ts = new TimerState();
//Threading.Timerオブジェクトの作成
//TimerState.Tickを0.1秒後に1秒間隔で実行する
ts.ThreadTimer =
new System.Threading.Timer(
new TimerCallback(ts.Tick), ts, 100, 1000);
//待機する
Console.ReadLine();
}
}
}}
上記コードの結果は例えば次のようになります。
#pre{{
システム起動後の経過時間:8315236ミリ秒(1)
システム起動後の経過時間:8316218ミリ秒(2)
システム起動後の経過時間:8317219ミリ秒(3)
システム起動後の経過時間:8318220ミリ秒(4)
システム起動後の経過時間:8319222ミリ秒(5)
Changed
システム起動後の経過時間:8319723ミリ秒(6)
システム起動後の経過時間:8320223ミリ秒(7)
システム起動後の経過時間:8320724ミリ秒(8)
システム起動後の経過時間:8321225ミリ秒(9)
システム起動後の経過時間:8321726ミリ秒(10)
Disposed
}}
参考:
-[[タイマ>http://www.microsoft.com/japan/msdn/library/ja/...
-[[スレッド タイマ>http://www.microsoft.com/japan/msdn/li...
-[[Timer クラス>http://www.microsoft.com/japan/msdn/libra...
***スレッドセーフなコレクションを使う [#c1a159cd]
System.Collections名前空間にあるコレクションクラス(Array...
コレクションをスレッドセーフにするためには、コレクション...
次にSynchronizedメソッドを使用した例を示します。
#code(vbnet){{
'using System.Collections;
'が宣言されているものとする
'同期されていないArrayListオブジェクトの作成
Dim al As New ArrayList
'alを同期するArrayListラッパーの取得
Dim syncdAl As ArrayList = ArrayList.Synchronized(al)
'同期されたArrayListオブジェクトの作成
Dim syncdAl2 As ArrayList = _
ArrayList.Synchronized(New ArrayList)
'同期されているか確かめる
Console.WriteLine("al.IsSynchronized = {0}", _
al.IsSynchronized)
Console.WriteLine("syncdAl.IsSynchronized = {0}", _
syncdAl.IsSynchronized)
Console.WriteLine("syncdAl2.IsSynchronized = {0}", _
syncdAl2.IsSynchronized)
}}
#code(csharp){{
//using System.Collections;
//が宣言されているものとする
//同期されていないArrayListオブジェクトの作成
ArrayList al = new ArrayList();
//alを同期するArrayListラッパーの取得
ArrayList syncdAl = ArrayList.Synchronized(al);
//同期されたArrayListオブジェクトの作成
ArrayList syncdAl2 = ArrayList.Synchronized(new ArrayList...
//同期されているか確かめる
Console.WriteLine("al.IsSynchronized = {0}",
al.IsSynchronized);
Console.WriteLine("syncdAl.IsSynchronized = {0}",
syncdAl.IsSynchronized);
Console.WriteLine("syncdAl2.IsSynchronized = {0}",
syncdAl2.IsSynchronized);
}}
#pre{{
出力結果;
al.IsSynchronized = False
syncdAl.IsSynchronized = True
syncdAl2.IsSynchronized = True
}}
コレクションの列挙はスレッドセーフな処理ではありませんの...
lockでコレクションをロックする時は、そのコレクション自身...
次にコレクションの列挙処理をスレッドセーフに行う例を示し...
#code(vbnet){{
'using System.Collections;
'が宣言されているものとする
'同期されたArrayList
Private Shared syncdAl As ArrayList = _
ArrayList.Synchronized(New ArrayList)
'エントリポイント
Public Shared Sub Main()
Dim i As Integer
For i = 0 To 99
syncdAl.Add(i)
Next i
'スレッドの作成と開始
Dim t As New Thread(New ThreadStart(AddressOf MyThrea...
t.Start()
'ちょっと待ってから、syncdAlを変更する
Thread.Sleep(500)
syncdAl.RemoveAt(0)
Console.ReadLine()
End Sub
Private Shared Sub MyThread()
'syncdAlをロックする
'これをしないと、例外がスローされる
SyncLock syncdAl.SyncRoot
'列挙処理をする
Dim i As Integer
For Each i In syncdAl
Console.Write(i)
Thread.Sleep(10)
Next i
End SyncLock
End Sub
}}
#code(csharp){{
//using System.Collections;
//が宣言されているものとする
//同期されたArrayList
private static ArrayList syncdAl =
ArrayList.Synchronized(new ArrayList());
//エントリポイント
public static void Main()
{
for (int i = 0; i < 100; i++)
{
syncdAl.Add(i);
}
//スレッドの作成と開始
Thread t = new Thread(new ThreadStart(MyThread));
t.Start();
//ちょっと待ってから、syncdAlを変更する
Thread.Sleep(500);
syncdAl.RemoveAt(0);
Console.ReadLine();
}
private static void MyThread()
{
//syncdAlをロックする
//これをしないと、例外がスローされる
lock(syncdAl.SyncRoot)
{
//列挙処理をする
foreach (int i in syncdAl)
{
Console.Write(i);
Thread.Sleep(10);
}
}
}
}}
ArrayクラスのようにSynchronizedメソッドがないコレクション...
参考:
-[[コレクションと同期 (スレッド セーフ)>http://www.micros...
***Interlockedの使い方 [#b33490fc]
以前「スレッドの同期」にて、「競合状態」の説明をしました...
lockステートメントによる同期により競合状態を防いでインク...
#code(vbnet){{
SyncLock Me
x += 1
End SyncLock
}}
#code(csharp){{
lock (this)
{
x++;
}
}}
実は.NET Frameworkではより優れた方法として、Interlocked.I...
上記のコードをInterlocked.Incrementメソッドで書き直すと、...
#code(vbnet){{
System.Threading.Interlocked.Increment(x)
}}
#code(csharp){{
System.Threading.Interlocked.Increment(x);
}}
Interlockedクラスの4つの静的メソッドIncrement、Decrement...
参考:
-[[Interlocked>http://www.microsoft.com/japan/msdn/librar...
-[[Interlocked クラス>http://www.microsoft.com/japan/msdn...
-[[スレッド処理のデザイン ガイドライン>http://www.microso...
**コメント [#x0ce129e]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2004-02-12 (木) 06:00:00,DOB...
ページ名:
▲
▼
[
トップ
] [
新規
|
子ページ作成
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]