2016-06-02 7 views
3

スレッドを使用してプログラムから複数のクライアント(PLC)に接続しています。プログラムはデータを送信し、PLCからの応答を受信します。デバッグモードでは(ブレークポイントをトグルする)、一度に1ステップずつプログラムが正常に動作します。それは、スレッドの1から来ています..しかし、私はただのブレークポイントを切り替えずにデバッグする場合に、応答イベントがCのスレッドモードからの適切なコールバック

Debugging mode with breakpoint:

...間違っている可能性がどのような...別のスレッドでも、同じIDを受信します以下は Debugging mode without breakpoint:

は私のコード

開始要求である:

private void StartRequest() 
{    
    foreach (ModbusTCP work in works) 
    { 
     work.Connect(); 
     Thread.Sleep(1000); 
     if (work.Connected) 
     { 
      try 
      { 
       Thread thread = new Thread(new ThreadStart(() => work.StartReadHoldingRegister())) { 
        Name = ((ReadHoldingRegisterParam)work.SetReadHoldingRegisterParam).id.ToString(), 
        IsBackground = true 
       }; 
       work.OnResponseEvent += new EventHandler<ModbusTCP.ResponseEventArgs>(modbus_OnResponseEvent); 
       work.OnExceptionEvent += new EventHandler<ModbusTCP.ExceptionEventArgs>(modbus_OnExceptionEvent);            
       thread.Start(); 
       threads.Add(thread); 
      } 
      catch (ThreadStateException ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 
     else 
      work.Disconnect(); 
    }    
} 

応答イベント

private void modbus_OnResponseEvent(object sender, ModbusTCP.ResponseEventArgs e) 
{ 
    lock (lockingObject) 
    { 
     if (e.data.Length > 0) 
     { 
      this.Dispatcher.BeginInvoke(new Action(() => 
      { 
       AddRow(RcvDataGrid, new PLCPacket() { 
        PLCId = e.id.ToString(), 
        PLCIp = "Test", 
        PLCTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt"), 
        PLCData = "" 
       }); 
      })); 
     } 
    } 
} 

答えて

4

あなたの変数workは、スレッド間で共有されます。スレッドが実行されると、変数workには何らかの値が入ります。それは、各スレッドがどのくらい速く処理されるかによって異なります。デバッガでコードをステップ実行すると、それを経験しません。匿名メソッドの前に値をキャプチャする場合

あなたは問題ないはずです。

try 
{ 
     // capture the current value of the loop variable 
     ModbusTCP localWork = work; 
     // so the anonymous method uses the reference in localWork 
     // instead of whatever value work has, which can be anywhere 
     // the future, worst case after your loop is finished, where 
     // work would hold the last value of the loop, and then 
     // start all threads with that value. 
     Thread thread = new Thread(
      new ThreadStart(
       () => localWork.StartReadHoldingRegister())) 
       { 
        Name = ((ReadHoldingRegisterParam) localWork.SetReadHoldingRegisterParam).id.ToString(), 
        IsBackground = true }; 
       }); 
     localWork.OnResponseEvent += new EventHandler<ModbusTCP.ResponseEventArgs>(modbus_OnResponseEvent); 
     localWork.OnExceptionEvent += new EventHandler<ModbusTCP.ExceptionEventArgs>(modbus_OnExceptionEvent);            
0

側のコメント:

lock (lockingObject) 
{ 
    if (e.data.Length > 0) 
    { 
     this.Dispatcher.BeginInvoke(new Action(() => 
     { 

このコードが正しいことはほとんどありません。ここでは、元のスレッドでロックを取得してから、新しいアクションasyncを送信します。ロックは現在のメソッドにスコープされているため、アクション自体の中ではなく、BeginInvoke呼び出しが返されるとすぐに解放されます。ロックによって実際に守られる操作は、e.data.Lengthチェックです。これはパラメータ(共有ではない)状態で動作し、したがって保護を必要としません。

アクション内にロックを配置する方が意味がありますが、アクションは常にメインスレッドで実行されるため、実際には保護は必要ありません(基本的にはシングルスレッドなので)。コード全体を見ることなく、あなたが達成しようとしているものを正確に推測するのは難しいですが、lock(lockingObject)は必要ない、または有用であることはほとんどありません。

+0

私はあなたのポイントを参照してください、実際にはロックはそこに始まっていませんでした。私はこの問題を解決しようと必死になっていて、どこでもロックを無作為に入れようとしていました。厄介なことに、私が見逃してしまったことに気づかなかったという良い説明が出てきます... **スレッドが実行されると、あなたの可変作業は** – mysayasan

関連する問題