2016-01-29 4 views
0

Моя цель: У меня есть 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, если он закрыт. Будет ли этот подход решать большинство проблем, о которых я говорил ранее?


Update: Моя другая проблема заключается в том, что различные объекты могут задавать различные параметры (скорость передачи данных и т.д.) в конструкторе - так я сталкиваюсь с проблемой :(так как я один статический m_port :(Что.. делать в таком случае ?? (? я мог бы ослабить это требование и сказать, что все объекты будут ставить одни и те же параметры в конструкторе, но это поможет)

+0

Вы не [спросить это уже] (http://stackoverflow.com/questions/35086242/writing-class-which-encapsulates-serial-port-which-might-be-used-also- по-многие-й)? –

+0

@MattBurland Nope удален, и это уточняется –

+0

Используйте одноэлементный шаблон. Не создавайте новые объекты 'HASPClass' и вместо этого используйте метод GetInstance (или что-то подобное), который будет возвращать статический экземпляр' HASPClass' (или создать его, если он еще не существует). –

ответ

0

простой синглтон шаблон может выглядеть следующим образом:

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 из родительского потока, чтобы он никогда не нуждался в вызове из любого другого потока.

+0

Спасибо - я прокомментировал выше и прокомментирую здесь тоже: (1) Действительно, мне нужно инициализировать этот класс с параметрами, такими как скорость передачи и т. Д. (2) Что произойдет, если какой-нибудь метод выкинет? Будет ли порт закрыт? Кто откроет порт? Я был бы признателен за отзывы от вас. Я также немного начинаю с .NET –

+0

@ user200312: вы можете передавать параметры в 'GetInstance', но если эти параметры могут измениться, то вы не можете использовать один и тот же объект (или на наименее, а не один и тот же базовый порт). Не ясно, ожидаете ли вы, что они изменится или нет (т. Е. Поток 1 имеет другую скорость передачи, чем поток 2). –

+0

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

0
class HASPCLass 
{ 
    static SerialPort m_port; 

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

(1) Это продолжение моего подхода? (2) Я предполагаю, что все инициализации параметров в методе Initializa? (3) Это работает, только если пользователям нужен мой класс, используя аналогичные параметры? например одинаковая скорость передачи и т. д.? –

+0

1) Вправо. 2) Вы передаете параметры в конструктор HASPClass(), а не в метод ** private ** Initialize. 3) Это работает в любом случае, однако после инициализации компонент будет работать с указанным бодом. Пока не будет вызван метод Close(). После закрытия его можно инициализировать с другой скоростью в бодах. – MobileX

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(); 
     } 
    } 
    } 
} 
+0

Этот вариант охватывает оба случая? Если мне нужно повторно инициализировать и без него? (Я думаю, что лучше заблокировать что-то еще, чем m_port, но это другая тема) –

+0

Как вы можете видеть, это так. Вы можете использовать отдельный объект для блокировки. – MobileX

Смежные вопросы