Многопоточность и последовательные порты - PullRequest
6 голосов
/ 29 марта 2012

Хорошо ... это будет долго, но мне нужно сначала объяснить некоторые предпосылки.

Эта часть моего программного обеспечения предназначена для сортировки предметов, бегущих по конвейерной ленте. Я использую Modbus для конвейерной ленты. Modbus откроет ворота в определенное время, чтобы пропустить предмет через ворота. Предметы будут проходить через определенные ворота в зависимости от веса.

Я наблюдаю за датчиком, чтобы определить, когда предмет находится в масштабе. Когда датчик заблокирован, предмет взвешивается и отправляется в соответствующие ворота. Таймеры настроены на открытие / закрытие ворот.

Мой код будет работать для этого .. проблема в том, что он не будет работать для нескольких элементов. Я имею в виду, что когда ворота открыты, датчик не контролируется, пока ворота не закрыты. Таким образом, пока пункт A находится на пути к воротам, элемент 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 и вылетает. Другие ошибки, которые я получаю, говорят: «Последовательный порт уже открыт» или «Ошибка ввода-вывода».

Ответы [ 3 ]

2 голосов
/ 29 марта 2012

Я думаю, тебе нужно что-то подобное. Не знаю, нужны ли блокировки, но я добавил их для безопасности, так как вы получаете ошибки

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 
        }
      } 
  } 
1 голос
/ 29 марта 2012

Я заметил, что у вас нет циклов в методах DoWork вашего потока. Это было бы отличным местом для начала. Рабочий поток должен быть циклом, который не возвращается, пока CancellationPending не будет установлен в true. Они не будут зацикливаться сами по себе только потому, что он у вас в потоке - поток будет работать до тех пор, пока он не будет завершен, а затем завершится.

Отредактировано, чтобы добавить: вам кажется, что вам не хватает того, что вам нужно разделить код, который контролирует масштаб, и код, который открывает и закрывает ворота. Одним из способов сделать это было бы иметь бесконечный цикл, который контролирует масштаб, и когда он что-то обнаруживает, он запускает новый поток, который обрабатывает открытие и закрытие ворот.

1 голос
/ 29 марта 2012

Я бы предположил, что вам лучше всего создать отдельный поток для каждого последовательного порта. Такой подход не потребует и не запретит какого-либо сходства в том, как обрабатываются порты, позволит избежать каких-либо помех в работе между портами и будет масштабируемым в разумных пределах (использование потока для каждого из 32 портов было бы хорошо; использование нить на каждую 1000 была бы плохой). Хотя следует избегать создания потоков, которые просто будут работать в течение короткого времени и завершать работу, или создания действительно огромного количества потоков, использование выделенного потока для каждого последовательного порта гарантирует, что при поступлении данных будет поток, готовый обработать его.

...