分類:[C#]
■開発環境
OS: Windows 10
NET Framework バージョン: 4.6.2
プログラミング言語: C#
開発ツール: Visual Studio Community 2017
補足: Visual Studio での C/C++ の開発経験は 20 年以上あります。
ある文字列を複数スレッドから読み書きする際の排他制御について教えて下さい。
ある文字列の使用は以下の様になります。
・メインスレッドで定期的に書き換える。
・サブスレッド(複数)で定期的に取得し、使用する。
尚、以下のフローは問題なしとします。
1. サブスレッド 1 が文字列を取得する。(文字列を保持するインスタンスのゲッター呼出し)
2. その直後にメインスレッドが文字列を書き換える。(文字列を保持するインスタンスのセッター呼出し)
3. サブスレッド 1 が取得した文字列を使用する。(この時点では書き換え前の文字列ですが、それは問題なしとする)
サブスレッドは使用の前に必ず文字列を取得する。
文字列の排他制御は以下のようなクラス(AもしくはB)のインスタンスを生成し、実現しようと思っています。
どちらのクラスを使用するのが正しいのでしょうか。
どちらも正しくない場合、どのようにしたらよいか教えて下さい。
クラスA:
ゲッターは保持している文字列と同じ内容の別文字列を渡します。(保持しているインスタンスとは別のインスタンスを渡す)
セッターは入力と同内容の別文字列を保持します。(入力とは別のインスタンスを保持)
クラスB:
ゲッターは保持している文字列そのものを渡します。(保持しているインスタンスを渡す)
セッターは入力の文字列そのものを保持します。(入力の文字列を保持)
クラスBでも良いと思ったのですが、1文字など短い文字列だった場合、文字はキャッシュメモリに配置され、他のスレッドからアクセスした場合には最新の内容に更新されていないメモリをアクセスする事態もあると思ったのですが、如何でしょうか。
クラスAとBの違いは以下の様に思っています。
・クラスAは文字列を構成する「各文字」を排他制御している。
・クラスBは文字列を「構成する文字が格納されているメモリの位置(つまりメモリアドレス)」を排他制御している(文字は排他制御していない)。
以下にクラスAとクラスBを示します。
class A
{
object _lockObj = new object();
string _strValue;
public string Value
{
get
{
string str;
lock( _lockObj )
{
if( _strValue == null )
{
str = null;
}
else
{
str = string.Copy( _strValue );
}
}
return str;
}
set
{
lock( _lockObj )
{
if( value == null )
{
_strValue = null;
}
else
{
_strValue = string.Copy( value );
}
}
}
}
}
class B
{
object _lockObj = new object();
string _strValue;
public string Value
{
get
{
string str;
lock( _lockObj )
{
str = _strValue;
}
return str;
}
set
{
lock( _lockObj )
{
_strValue = value;
}
}
}
}
|