(注: .Net 4.0 の将来のアイデアが欲しいのですが、このプロジェクトでは .Net 3.5 に限定されています。)
外部デバイスからデータを非同期的に読み取り (これまでになく創造的な strSomeData によるコード例でシミュレートされています:-)、それを StringBuilder の「バッファ」(strBuilderBuffer :-) に格納するスレッドがあります。
「メイン コード」では、この「バッファ」を「ニブル」したいと考えています。ただし、「操作」の観点から、スレッドセーフな方法でこれを行う方法についてはわかりません。msdn によると、「この ( StringBuilder
) 型の public static メンバーはすべてスレッド セーフです。インスタンス メンバーは、スレッド セーフであることが保証されていません。」ただし、以下のコードは、「運用」の観点から、スレッドセーフではない可能性があることを示しています。
重要なのは、次の 2 行のコードが気になるということです。
string strCurrentBuffer = ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer.ToString();
// Thread 'randomly' slept due to 'inconvenient' comp resource scheduling...
ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer.Length = 0;
コンピューターの OS がバッファーの「読み取り」とバッファーの「クリア」の間にスレッドをスリープ状態にすると、データが失われる可能性があります (これは悪いことです :-(
「原子性」を保証する方法はありますか? これらの2行のうち、コンピューターがそれらを中断しないように強制しますか?
の使用に関する以下のVladの提案に関してlock
、私はそれを試しましたが、うまくいきませんでした(実際にはまったく):
public void BufferAnalyze()
{
String strCurrentBuffer;
lock (ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer)
{
strCurrentBuffer = ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer.ToString();
Console.WriteLine("[BufferAnalyze()] ||<< Thread 'Randomly' Slept due to comp resource scheduling");
Thread.Sleep(1000); // Simulate poor timing of thread resourcing...
ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer.Length = 0;
}
Console.WriteLine("[BufferAnalyze()]\r\nstrCurrentBuffer[{0}] == {1}", strCurrentBuffer.Length.ToString(), strCurrentBuffer);
}
スレッドセーフバッファを実装するより良い方法はありますか?
完全なコードは次のとおりです。
namespace ExploringThreads
{
/// <summary>
/// Description of BasicThreads_TestThreadSafety_v1a
/// </summary>
class ThreadWorker_TestThreadSafety_v1a
{
private Thread thread;
public static StringBuilder strBuilderBuffer = new StringBuilder("", 7500);
public static StringBuilder strBuilderLog = new StringBuilder("", 7500);
public bool IsAlive
{
get { return thread.IsAlive; }
}
public ThreadWorker_TestThreadSafety_v1a(string strThreadName)
{
// It is possible to have a thread begin execution as soon as it is created.
// In the case of MyThread this is done by instantiating a Thread object inside MyThread's constructor.
thread = new Thread(new ThreadStart(this.threadRunMethod));
thread.Name = strThreadName;
thread.Start();
}
public ThreadWorker_TestThreadSafety_v1a() : this("")
{
// NOTE: constructor overloading ^|^
}
//Entry point of thread.
public void threadRunMethod()
{
Console.WriteLine("[ThreadWorker_TestThreadSafety_v1a threadRunMethod()]");
Console.WriteLine(thread.Name + " starting.");
int intSomeCounter = 0;
string strSomeData = "";
do
{
Console.WriteLine("[ThreadWorker_TestThreadSafety_v1a threadRunMethod()] running.");
intSomeCounter++;
strSomeData = "abcdef" + intSomeCounter.ToString() + "|||";
strBuilderBuffer.Append(strSomeData);
strBuilderLog.Append(strSomeData);
Thread.Sleep(200);
} while(intSomeCounter < 15);
Console.WriteLine(thread.Name + " terminating.");
}
}
/// <summary>
/// Description of BasicThreads_TestThreadSafety_v1a.
/// </summary>
public class BasicThreads_TestThreadSafety_v1a
{
public BasicThreads_TestThreadSafety_v1a()
{
}
public void BufferAnalyze()
{
string strCurrentBuffer = ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer.ToString();
Console.WriteLine("[BufferAnalyze()] ||<< Thread 'Randomly' Slept due to comp resource scheduling");
Thread.Sleep(1000); // Simulate poor timing of thread resourcing...
ThreadWorker_TestThreadSafety_v1a.strBuilderBuffer.Length = 0;
Console.WriteLine("[BufferAnalyze()]\r\nstrCurrentBuffer[{0}] == {1}", strCurrentBuffer.Length.ToString(), strCurrentBuffer);
}
public void TestBasicThreads_TestThreadSafety_v1a()
{
Console.Write("Starting TestBasicThreads_TestThreadSafety_v1a >>> Press any key to continue . . . ");
Console.Read();
// First, construct a MyThread object.
ThreadWorker_TestThreadSafety_v1a threadWorker_TestThreadSafety_v1a = new ThreadWorker_TestThreadSafety_v1a("threadWorker_TestThreadSafety_v1a Child");
do
{
Console.WriteLine("[TestBasicThreads_TestThreadSafety_v1a()]");
Thread.Sleep(750);
BufferAnalyze();
//} while (ThreadWorker_TestThreadSafety_v1a.thread.IsAlive);
} while (threadWorker_TestThreadSafety_v1a.IsAlive);
BufferAnalyze();
Thread.Sleep(1250);
Console.WriteLine("[TestBasicThreads_TestThreadSafety_v1a()]");
Console.WriteLine("ThreadWorker_TestThreadSafety_v1a.strBuilderLog[{0}] == {1}", ThreadWorker_TestThreadSafety_v1a.strBuilderLog.Length.ToString(), ThreadWorker_TestThreadSafety_v1a.strBuilderLog);
Console.Write("Completed TestBasicThreads_TestThreadSafety_v1a >>> Press any key to continue . . . ");
Console.Read();
}
}
}