2017-01-11 6 views
0

をもたらし、私の質問です: C#ロックを同時に/書き込みおよび表示を読むためには、ここで

が、私はこのプログラムを持っていると言う(私はできる限りをsemplifyしようとするでしょう): receiveResultThread貴様ネットワークからの結果のために待ち displayResultToUIThreadは受信したすべての結果をUIに反映します。

class Program 
{ 
    private static Tests TestHolder; 

    static void Main(string[] args) 
    { 
     TestHolder = new Tests(); 

     Thread receiveResultsThread = new Thread(ReceiveResult); 
     receiveResultsThread.Start(); 

     Thread displayResultToUIThread = new Thread(DisplayResults); 
     displayResultToUIThread.Start(); 

     Console.ReadKey(); 
    } 

    public static void ReceiveResult() 
    { 
     while (true) 
     { 
      if (IsNewTestResultReceivedFromNetwork()) 
      { 
       lock (Tests.testLock) 
        TestHolder.ExecutedTests.Add(new Test { Result = "OK" }); 
      } 

      Thread.Sleep(200); 
     } 
    } 

    private static void DisplayResults(object obj) 
    { 
     while (true) 
     { 
      lock (Tests.testLock) 
      { 
       DisplayAllResultInUIGrid(TestHolder.ExecutedTests); 
      } 

      Thread.Sleep(200); 
     } 
    } 
} 

class Test 
{ 
    public string Result { get; set; } 
} 

class Tests 
{ 
    public static readonly object testLock = new object(); 
    public List<Test> ExecutedTests; 

    public Tests() 
    { 
     ExecutedTests = new List<Test>(); 
    } 
} 

class UIManager 
{ 
    public static void DisplayAllResultInUIGrid(List<Test> list) 
    { 
     //Code to update UI. 
    } 
} 

範囲は、他のスレッドがリストにテストを追加し、それを使用しても安全であるされている間UIを更新しないことであることを考慮:

lock (Tests.testLock) 

か、私が使用する必要があります。

lock (TestHolder.testLock) 

(testLockの静的プロパティを変更しています)?

これはこの種のプログラムを書く良い方法だと思いますか、より良いパターンを提案できますか?

ありがとうございました!

+1

msdn:https://msdn.microsoft.com/en-us/library/kzy257t0(v=vs.110).aspx – jdweng

+1

を参照してください。どのフレームワークをターゲットにしていますか? 4.0以上を使用している場合は、タスクを使用する必要があるため、これを尋ねます。https://msdn.microsoft.com/en-us/library/dd537609(v=vs.100).aspx – taquion

答えて

1

公開している(public staticについては公開していません)ロックオブジェクトは危険です。参照してくださいhere

公開オブジェクトをロックするのが悪い習慣である理由は、ELSEがそのオブジェクトでロックしているかどうかを決して確かめることができないからです。

さらに、 List<T>を持っていて、外側のスコープからオブジェクトを追加するだけで、匂いになる可能性があります。私の意見で

あなたのテストクラスのクライアントが正しくロックオブジェクトを使用して心配する必要はありません

class Tests 
{ 
    private static readonly object testLock = new object(); 
    private List<Test> executedTests; 

    public Tests() 
    { 
     ExecutedTests = new List<Test>(); 
    } 

    public void AddTest(Test t) 
    { 
     lock(testLock) 
     { 
      executedTests.Add(t); 
     } 
    } 

    public IEnumerable<Test> GetTests() 
    { 
     lock(testLock) 
     { 
      return executedTests.ToArray(); 
     } 
    } 
    [...] 
} 

Tests方法AddTestを持っている良いアイデアだろう。正確に言えば、彼らはあなたのクラスの内部について心配する必要はありません。

とにかく、あなたのクラスの名前をConcurrentTestsCollectionなどの名前に変更すると、そのクラスのユーザーはある程度スレッドセーフであることがわかります。

+0

Shouln't be: ロックtestLock) 戻り値executeTests.ToArray(); ? –

+0

@DanieleArrighiええ、thx。これを修正しました。 –

0

タスクと非同期/待機キーワードを使用してこれを冗長にすることはできますが、私はあなたの質問を完全に解決するとは思いません。

ExecuteTestsは、スレッドセーフにしたいリスト(またはそのようなもの)であると想定します。そのため、アクセスする際にロックを作成するのはなぜですか。

私は、リスト自体を、それに対する操作ではなくスレッドセーフにします。これにより、ロックまたはロックオブジェクトが不要になります。

これを自分で実装することも、System.Collections.Concurrent名前空間で何かを使用することもできます。

P.S.

プロセスが終了したときにスレッドが終了(中止)される場合は、スレッドのIsBackgroundプロパティをtrueに設定する必要があります。

+0

ご返信ありがとうございます。私はこのように行くと思う。実際のプログラムではすべてのスレッドがバックグラウンドにあります。これはちょうどコードを短縮することでした。ありがとう! –

関連する問題