我可以开始一个线程,其中包含一个打开的 System.IO.SerialPort 吗?

huangapple go评论91阅读模式
英文:

Can I start a thread, with an argument containing an open System.IO.SerialPort?

问题

我正在使用C#编写一个面向对象的应用程序来控制电源供应。电源供应使用串口来进行控制。我想将SelectedPowerSupply类的对象放入一个线程中,以在指定的时间更改电压并打开或关闭电源供应。

我遇到的问题是,每当我将System.IO.SerialPort串口放入线程中时,串口不再工作。是否可能将串口放入线程中,或者这是一个硬性限制?在我当前的情况下,我将一个名为SelectedPowerSupply的类传递到线程中,其中串口在线程启动时处于打开状态。

我认为可能有以下几种可能性:

  1. 我可能缺少一些细节或步骤,允许我将已打开的串口传递到线程中并使其工作。
  2. 我必须关闭串口,然后在线程中重新打开它。
  3. 我必须将串口从线程外部保留,并使用不同的机制将消息传递给它。

以下是Visual Studio 2022中的设置:
.NET 7.0,Windows应用程序,支持的操作系统版本为7.0

//SelectedSupply包含串口,它在线程外部完美工作

public class Power_Supply_Multi_Output_Class
{
  private static System.IO.Ports.SerialPort serial_port = new System.IO.Ports.SerialPort();
  //其他电源供应类的代码在此
}

TestThread = new Thread(() => TestThreadProc(ref ThreadStop, ref SelectedSupply));
TestThread.Start();

// ThreadStop是在线程中用于结束线程的布尔值
// 通过完成测试或从GUI中停止它,ThreadStop可以设置为true。这就是为什么它被传递为ref参数的原因

while (!Stop_Thread && selected_supply != null)
{
if (test-condition1)//测试并且在线程外部工作
{
serial_port.Write(Message); // <-在线程内部不起作用,在线程外部起作用
转到test-condition2
}
else if (test-condition2)//测试并且在线程外部工作
{
serial_port.Write(Message); // <-在线程内部不起作用,在线程外部起作用
Stop_Thread = true;
}

Thread.Sleep(100);
}


<details>
<summary>英文:</summary>

I&#39;m writing an object oriented application in C# to control a power supply. The power supply uses a serial port to control the supply.  I want to put the `SelectedPowerSupply` class object into a thread to change voltages and turn on and off the supply at specified times.

The problem that I see is that anytime I put the `System.IO.SerialPort` serial port into the thread, the serial port no-longer works.  Is it possible to put a serial port in a thread, or is this a hard stop?  In my current case, I&#39;m passing a class, `SelectedPowerSupply`, into the thread where the serial port is open during the time when the thread is started.  

I assume there may be the following possibilities
1. I am missing some detail or step allow me to pass an open serial port into a thread and have it work.
2. I must close the serial port and open it in the thread.
3. I must keep the serial port out of the thread an use a different mechanism to pass the messages to it outside the thread.

Here are the settings within Visual Studio 2022
.NET7.0, Windows Application, Supported OS Version 7.0

    ```
//SelectedSupply contains the serial port and it works perfectly outside of the thread
    
    public class Power_Supply_Multi_Output_Class
    {
      private static System.IO.Ports.SerialPort serial_port = new System.IO.Ports.SerialPort();
      //other power supply class code here
    }
        
    TestThread = new Thread(() =&gt; TestThreadProc(ref ThreadStop, ref SelectedSupply));
    TestThread.Start();
    ```
    
    //ThreadStop is a bool used in the thread to end the thread
    //ThreadStop can be set to true by completing the test or by stopping it from the GUI  This is why it&#39;s passed as ref
    
    while (!Stop_Thread &amp;&amp; selected_supply != null)
    {
      if(test-condition1)//tested and works
      {
        serial_port.Write(Message);  &lt;-does not work inside the thread, works outside the thread
        move to test-condition2
      }
      else if(test-condition2)//tested and works
      {
        serial_port.Write(Message);  &lt;-does not work inside the thread, works outside the thread
        Stop_Thread = true;
      }
    
      Thread.Sleep(100);
    }

</details>


# 答案1
**得分**: 2

对象不包含在线程内。对象所在的内存由进程中的所有线程共享。对对象的访问,如属性读取、属性写入和方法调用,确实发生在线程内。如果两个线程访问同一个对象,通常需要进行一些同步。

串口对象具有相当好的线程安全性。您可以打开它一次,然后让多个线程进行读写操作。但是,虽然某些操作可以很好地重叠(读和写),但其他操作则根本不能重叠(读和关闭,写和关闭),而其他操作如果重叠可能会产生不可预测的结果(例如两个写操作,您无法知道哪一个会先完成,而且两个线程的数据块甚至可能互相交错)。

然后,System.IO.Ports.SerialPort 类中存在大量永远无法修复的错误,因为这样做将需要以不兼容的方式更改公共接口。

您似乎还在您自己的类之间共享变量,没有迹象表明您的类是线程安全的。对于像用于停止工作的标志这样的东西,应用`volatile`关键字可能足够。

<details>
<summary>英文:</summary>

Objects aren&#39;t contained inside of threads.  The memory where objects live is shared by all threads in a process.  Accesses to the object, like property reads, property writes, and method calls, do happen inside of threads.  And if two threads access the same object, you usually need some synchronization.

A serial port object has pretty good thread safety.  You can open it once and then have multiple threads reading and writing.  But while some operations can overlap just fine (a read and a write), others can&#39;t at all (a read and close, write and close), and others will do unpredictable things if overlapped (in the case of two writes, you don&#39;t know which will come out first, and chunks from the two threads could even get interleaved with each other).

And then there are a myriad of bugs in the System.IO.Ports.SerialPort class that can never be fixed, because doing so would require changing the public interface in incompatible ways.

You also appear to be sharing variables in your own class between your threads, and there&#39;s no sign that you have made your class threadsafe.  For something like a flag to stop the work, it may be sufficient to apply the `volatile` keyword.

</details>



huangapple
  • 本文由 发表于 2023年7月13日 21:58:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76680219.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定