2016-07-23 5 views
1

マルチスレッド環境では、この拡張メソッドはスレッドセーフですか?は、C#拡張メソッドのスレッドセーフを使用してXElement値を読み取っていますか?

class Program 
{ 
    public static object lockObject = new object(); 
    static void Main(string[] args) 
    { 
     List<Student> studentCollection = new List<Student>(); 

     string xml = "<root>"; 
     xml += "<student><name>stud1</name><address>street1</address></student>"; 
     xml += "<student><name>stud2</name><address>street2</address></student>"; 
     xml += "<student><name>stud3</name><address>street3</address></student>"; 
     xml += "</root>"; 

     Parallel.For(0, 10000, index => 
     { 
      XElement xmlElement = XElement.Parse(xml); 
      var students = xmlElement.Descendants("student").ToList(); 
      students.ForEach(student => 
      { 
       Student stud = new Student(); 
       stud.Name = student.GetValue("name"); 
       stud.Address = student.GetValue("address"); 
       lock (lockObject) 
       { 
        studentCollection.Add(stud); 
       } 

      }); 

     }); 
    }  
} 

public static class Extension 
{ 
    public static string GetValue(this XElement xelement, string tagName) 
    { 
     var ele = xelement; 

     if (ele != null && ele.Element(tagName) != null) 
     { 
      // I assume this as unsafe code. 
      return ele.Element(tagName).Value; 
     } 
     return string.Empty; 
    } 
} 
+2

なぜあなたはそうではないと思いますか? – Rahul

+3

xelementが変更できる場合は、いいえ。それができない場合は、はい。両方のケースをスレッドセーフにするには、ele.Element(tagName)を変数に保存し、それを使用します。 – Euphoric

+0

Euphoricのコメントを拡張するには、C#6を使用する場合、メソッドを次のように書き換えます。 'return ele?.Element(tagName)?Value ?? string.Empty; ' スレッドセーフでもあります('? '演算子はnullチェックや使用前にテンポラリ変数にそのオペランドを格納します) –

答えて

2

拡張メソッドは、オブジェクト*の状態を変更しないため、本質的にスレッドセーフです。

状態を変更する可能性のある引数が渡された場合、メソッドの呼び出しやプロパティの設定は行いません。もしそれがあったとしても、それはスレッドセーフであると考えることができます。問題は、他のオブジェクトのメソッドとプロパティがスレッドセーフであるかどうかです。

実際にXElementのプロパティがスレッドセーフであるかどうかを確認しているようです。ではない。同時更新とその読み込みを安全に行うことはできません。しかし、やはりそれはXElementであり、あなたの拡張方法ではありません。

複数のスレッドがオブジェクトに対して安全でない読み取り/書き込みを試みる可能性がある場合は、lockなどのメカニズムを使用してオブジェクトへのアクセスを制御する必要があります。そのオブジェクトを別のメソッドに渡すと、100%保証されたアトミック操作を実行する方法がない限り、そのメソッドが実行できる方法はありません。

コードの特定の行をどのようにコンパイルしてアトミックなものかどうかを判断する方法について詳しくはお勧めしません。それがInterlocked.Incrementのようなものであれば、その目的のためにが存在します。、素晴らしいです。それとも、それが原子であることが明示的に書かれているBooleanのようなものであれば。それ以外は、オブジェクトを複数のスレッドからのアクセスから保護するだけです。

私はを推測しています。あなたはこれを議論の対象にするXMLを読んでいるだけです。これらの要素を構築していれば、値をすでに知っていて、変更するのと同時にXMLから読み取る必要はありません。ちょうど推測。


は明確にするため、ここではないスレッドセーフです拡張メソッドの例です。

public static class StringTrimExtensions 
{ 
    public static int CharactersTrimmed {get; private set;} 

    public static string Trim(this string input) 
    { 
     var trimmed = input.Trim(); 
     CharactersTrimmed = CharactersTrimmed + (input.Length - trimmed.Length); 
     return trimmed; 
    } 
} 

(それは。全く役に立たない方法です)。しかし、それは非スレッドセーフな方法で自身の状態を変更しているため、それはスレッドセーフではありません。したがって、複数のスレッドから使​​用されている場合、トリムされた文字の数が壊れる可能性があります。

ただし、合計値の更新がアトミックであることを保証するように変更すると、このメソッドはスレッドセーフになります。

public static class StringTrimExtensions 
{ 
    private static int _charactersTrimmed; 
    public static int CharactersTrimmed { get {return _charactersTrimmed;} } 

    public static string Trim(this string input) 
    { 
     var trimmed = input.Trim(); 
     var countOfTrimmedCharacters = input.Length - trimmed.Length; 
     Interlocked.Add(ref _charactersTrimmed, countOfTrimmedCharacters); 
     return trimmed; 
    } 
} 

あるいは、デモンストレーションのために、我々は同時にCharactersTrimmedの更新から、複数のスレッドを防ぐためにlockを使用することができます。 (私達はちょうどこのように数字を追加している場合は、Interlockedは、より多くの意味があります。)

public static class StringTrimExtensions 
{ 
    public static int CharactersTrimmed { get; private set; } 
    private static readonly object CharactersTrimmedLock = new object(); 

    public static string Trim(this string input) 
    { 
     var trimmed = input.Trim(); 
     lock (CharactersTrimmedLock) 
     { 
      CharactersTrimmed += (input.Length - trimmed.Length); 
     } 
     return trimmed; 
    } 
} 

しかし、いずれかの方法を、私たちはInterlockedまたはlockを使用して危険な動作を防止するかどうか、我々は法のスレッドセーフ作りました。

+0

hmm ... XElementのプロパティがどこで同時かどうかはわかりません。型の見直しは「この型のpublic static(Visual BasicのShared)メンバはスレッドセーフです」を示しています。 .. –

+0

ああ..おそらく私があなたが示していたものを間違って読んでしまった –

+1

あなたが引用しているのと同じ文書から。 'Element'は' XElement'の* static *メソッドではなく、 'Name'は静的プロパティではありません。 –

関連する問題