创建类以使用串行端口

时间:2016-01-29 16:31:17

标签: c# serial-port

我的目标:我有HASP与我需要使用串口进行通信。 事情是来自不同线程的许多函数可能想要与此HASP进行通信 - 我希望发生一些同步。

我做了什么:我创建了名为HASPClass的包装类。看起来像这样:

class HASPCLass
{
  SerialPort m_port;
  HASPClass(..)
  {
    //..  Init some other properties
    m_port.Open();
    //..
  }
  void CustomWriteToHASP()
  {
    //.. Do something
    m_port.Write(...);
  }
  void CustomReadHASP()
  {
    //.. Do something
    m_port.Read(...);
  }
  void Close () 
  {
   //Some code to close m_port
  };
}

这个类的用法是:

来自某个线程的Function1:

HASPClass o = new HASPClass(..);
o.CustomWriteToHASP(..)

来自其他线程的Function2:

HASPClass o1 = new HASPClass(..);
o1.CustomReadHASP(..)

问题1 :现在,如果o未关闭m_port,则o1的构造函数将自从端口打开后抛出。 我想避免这种情况,让o1等待o完成工作。

我的想法:也许我应该m_port静态 - 并在HASPClass中使用静态锁,它会解决上述问题吗?此外,构造函数将更改为仅在打开静态m_port 时打开。这种方法会解决我之前概述的大部分问题吗?

更新:我的另一个问题是不同的对象可能在构造函数中指定了不同的参数(波特率等) - 所以我遇到了一个问题:(因为我有单个静态m_port。 :(。在这种情况下该做什么?(我可以放宽这个要求并说所有对象都会在构造函数中放置相同的参数,但它会有帮助吗?

3 个答案:

答案 0 :(得分:1)

简单的单例模式可能如下所示:

class HASPClass
{
  private static HASPClass _instance;

  private HASPClass(..)
  {
    //..  Init some other properties

  }

  public static GetInstance(...)
  {
      // Note, if called with different parameters then this will be
      // quite a bit more complicated
      if (_instance == null) 
      { 
          _instance = new HASPClass(...)
      }
      return _instance;
  }
}

现在,当你打电话时,你会做类似的事情:

HASPClass o = HASPClass.GetInstance(..);
o.CustomWriteToHASP(..)

但是......因为你是多线程的,所以这种模式不安全。您需要在关键GetInstance部分周围实施一些锁定,以确保不创建多个对象。所以你可以这样做:

  private static object lockObj = new object();
  public static GetInstance(...)
  {
      // Note, if called with different parameters then this will be
      // quite a bit more complicated
      if (_instance == null) 
      { 
          lock (lockObj)
          {
              if (_instance == null)
              {
                  _instance = new HASPClass(...)
              }
          }
      }
      return _instance;
  }

比手动锁定更好的是使用Lazy,但如果需要传递参数,这可能会很复杂。如果(我假设)这些参数只传递一次,您可能希望有一个单独的初始化函数来存储这些参数,这样您就不需要在获得实例时传递它们。

如果参数每次都相同,你可以尝试这样的事情:

class HASPClass
{
    private static ParameterObject _parameters;

    private static Lazy<HASPClass> _instance = new Lazy<HASPClass>(() => 
    {
        if (_parameters == null) 
        {
            throw new InvalidOperationException("Can get instance before initializing");
        }
        return new HASPClass(_parameters);
    });

    public static HASPClass Instance
    {
       get { return _instance.Value; }
    }

    private HASPClass(ParametersObject parameters)
    {
        // create and populate your object using values from parameters
    }

    public static void Initialize(ParameterObject parameters)
    {
        if (_parameters != null) 
        {
            // you might throw an exception here if this is not allowed
            // Or you might drop and recreate your object if it is allowed
        }
        _parameters = parameters;
    } 
}

您可能需要或可能不需要锁定Initialize,但您的想法是,您可能首先从父线程调用Initialize,以便永远不需要再次调用它任何其他线程。

答案 1 :(得分:0)

class HASPCLass
{
  static SerialPort m_port;

  HASPClass(..)
  {
    lock(m_port)
    {
       if (!Initialized())
       {
         Initialize();
       }
    }
  }
  void Close () 
  {
    lock(m_port)
    {
       if (Initialized())
       {
         Uninitialize();
       }
    }
  }
}

答案 2 :(得分:0)

这是为您提供的另一个代码变体。它应该在任何情况下都有效。如果请求的波特率不同,它会重新打开端口。

class HASPCLass
{
  private static SerialPort m_port;
  private static bool m_initialized;
  private static int m_baudRate;

  public HASPClass(int baudRate)
  {
    lock(m_port)
    {
       if (!m_initialized)
       {
         Initialize(baudRate);
       }
    }
  }

  private Initialize()
  {
     m_port.open(baudRate);
     m_baudRate = baudRate;
     m_initialized = true;
  }

  private Uninitialize()
  {
     m_port.close();
     m_initialized = false;
  }

  private ReinitializeIfNeeded(int baudRate)
  {
     if (baudRate != m_baudRate)
     {
        Uninitialize();
        Initialize(baudRate);
     }
  }

  public void Read(int baudRate, out buff) 
  {
    lock(m_port)
    {
      ReinitializeIfNeeded(baudRate);
      m_port.Read(out buff);
    }
  }

  public void Write(int baudRate, in buff) 
  {
    lock(m_port)
    {
      ReinitializeIfNeeded(baudRate);
      m_port.Write(buff);
    }
  }

  public void Close() 
  {
    lock(m_port)
    {
       if (m_initialized)
       {
         Uninitialize();
       }
    }
  }
}