多线程和串行端口

时间:2012-03-28 20:12:58

标签: c# multithreading serial-port modbus

好的..这将是漫长的,但我需要首先解释一些背景。

我的软件的这一部分用于分拣传送带上的物品。 我正在使用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并崩溃。我得到的其他错误说“串口已经打开”或“I / O错误”。

3 个答案:

答案 0 :(得分: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 
        }
      } 
  } 

答案 1 :(得分:1)

我建议您最好的选择是创建一个专用线程来坐在每个串口上。这种方法既不需要也不禁止在端口处理方面有任何相似之处,将避免端口之间的任何操作干扰,并且可以在合理范围内进行扩展(对32个端口中的每个端口使用一个线程都可以;使用1000个中的每一个的线程都很糟糕)。虽然应该避免创建只运行很短时间并退出或创建大量线程的线程,但是为每个串行端口使用专用线程将确保在数据进入时将有一个线程准备好处理它。

答案 2 :(得分:1)

我注意到你的线程的DoWork方法中没有任何循环。这将是一个很好的起点。工作线程应该是一个循环,在CancellationPending设置为true之前不会返回。它们不会因为你在一个线程中拥有它而自行循环 - 线程将一直运行直到它完成,然后退出。

编辑添加:您似乎缺少的是您需要拆分监控比例的代码以及打开和关闭门的代码。一种方法是使用一个监视比例的无限循环,当它检测到某些东西时,它会启动一个处理打开和关闭门的新线程。