6

わかりました..これは長くなりますが、最初に背景を説明する必要があります.

私のソフトウェアのこの部分は、コンベア ベルトを下っていくアイテムを分類するためのものです。コンベアベルトにはModbusを使用しています。Modbus は特定の時間にゲートを開き、アイテムがゲートを通過できるようにします。アイテムは重量に基づいて特定のゲートを通過します。

アイテムがはかりに載っていることを判断するためにセンサーを監視しています。センサーがブロックされると、アイテムは計量され、適切なゲートに送られます。ゲートの開閉にはタイマーが設定されています。

私のコードはこれで機能します..問題は、複数のアイテムでは機能しないことです。つまり、ゲートが開いている間は、ゲートが閉じられるまでセンサーは監視されません。そのため、アイテム A がゲートに向かう途中で、アイテム B がセンサーをブロックしても、アイテム B ははかりで計量されません。一度に最大 8 個のアイテムを並べることができました。ここに私が今実行しているコードがあります:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e)
{
    if (SensorThread.CancellationPending == true)
        e.Cancel = true;
    else
    {
        ReadSensor();
    }    
}

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //if sensor is blocked
    if (sensorstatus == 0)
    {
        //the timers just start the thread
        scaleTimer.Start();
    }
    else
    {
        sensorTimer.Start();
    }
}

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e)
{
  if (ScaleThread.CancellationPending == true)
    {
        e.Cancel = true;
    }
    else
    {
        ReadScale();
        //SaveWeight();
        prevgate = gate;
        gate = DetermineGate();
        SetOpenDelay();
        SetDuration();
    }
  }

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //if gate = 0, this means the weight of meat on scale 
    //is not in any weight range. Meat runs off the end.
    if (gate == 0)
    {
        txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                                                                                "lbs is out of range"});
        sensorTimer.Start();
    }
    else
    {
      //open gate
      //then close gate
    }
  }

このコードは正常に機能します。行の複数の項目を説明できるようにする必要があるだけです。助言がありますか????

私も次のことを試しました:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e)
{
    if (SensorThread.CancellationPending == true)
        e.Cancel = true;
    else
    {
        ReadSensor();
    }    
}    

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  sensorTimer.Start();
}

  private void ScaleThread_DoWork(object sender, DoWorkEventArgs e)
{
  if (ScaleThread.CancellationPending == true)
    {
        e.Cancel = true;
    }
    else
    {   
        //sensor blocked
        if (sensorstatus == 0)
        {
          ReadScale();
          //SaveWeight();
          prevgate = gate;
          gate = DetermineGate();
          SetOpenDelay();
          SetDuration();

          //if gate = 0, this means the weight of meat on scale 
          //is not in any weight range. Meat runs off the end.
          if (gate == 0)
          {
            txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                                                                                "lbs is out of range"});
          }
          else
          {
            //open gate
            //close gate
          }
    }
}

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   scaleTimer.Start();
}

これを行うと、開始ボタンが押されたときに両方のスレッドを開始しました。あらゆる種類の例外が発生し、プログラムは最終的に SEHException をスローしてクラッシュします。私が得る他のエラーは、「シリアルポートはすでに開いています」または「I / Oエラー」と言います。

4

3 に答える 3

2

このようなものが必要だと思います。ロックが必要かどうかはわかりませんが、エラーが発生しているため、安全のために追加しました

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{
    int sensor = 1;
    while(!SensorThread.CancellationPending == true) 
    {
        int newSensor;
        lock(this)
        {
            newSensor = ReadSensor(); 
        }

        //sensor state changed
        if(newSensor != sensor)
        {
            //sensor was 1 and changed to 0
            if(newSensor==0)
            {
               scaleTimer.Start(); 
            }
            sensor = newSensor;
        }
        Thread.Sleep(1);
    }
    e.Cancel = true; 
}     

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //sensor blocked 
    //if (sensorstatus == 0) 
    { 
        lock(this)
        {
            ReadScale(); 
        }
        //SaveWeight(); 
        prevgate = gate; 
        gate = DetermineGate(); 
        lock(this)
        {
            SetOpenDelay(); 
            SetDuration(); 
        }

      //if gate = 0, this means the weight of meat on scale  
      //is not in any weight range. Meat runs off the end. 
      if (gate == 0) 
      { 
        txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() +  
                                                                            "lbs is out of range"}); 
      } 
      else 
      { 
        lock(this)
        {
        //open gate 
        }
        lock(this)
        {
        //close gate 
        }
      } 
  } 
于 2012-03-28T21:30:10.663 に答える
1

おそらく最善の策は、各シリアルポートに専用のスレッドを作成することです。このようなアプローチは、ポートの処理方法の類似性を要求も禁止もせず、ポート間の操作の干渉を回避し、合理的な範囲内でスケーラブルになります (32 個のポートのそれぞれにスレッドを使用しても問題ありません。 1,000 ごとにスレッドを作成するのは適切ではありません)。単純に短時間実行して終了するスレッドを作成したり、非常に膨大な数のスレッドを作成したりすることは避けるべきですが、各シリアル ポートに専用のスレッドを使用すると、データが入ってきたときにそれを処理する準備ができているスレッドが存在することが保証されます。

于 2012-03-28T20:34:39.860 に答える
1

スレッドの DoWork メソッドにループがないことに気付きました。それは始めるのに最適な場所です。ワーカー スレッドは、CancellationPending が true に設定されるまで戻らないループである必要があります。スレッド内にあるという理由だけでループすることはありません。スレッドは完了するまで実行され、終了します。

追加するために編集:不足しているように見えるのは、スケールを監視するコードと、ゲートを開閉するコードを分割する必要があることです。これを行う 1 つの方法は、スケールを監視する無限ループを作成し、何かを検出すると、ゲートの開閉を処理する新しいスレッドを開始することです。

于 2012-03-28T20:35:42.263 に答える