Освободить последовательный порт должным образом - PullRequest
7 голосов
/ 06 декабря 2010

Я пишу приложение на c #, которое использует класс SerialPort для связи с несколькими устройствами.Теперь большая проблема, с которой я сталкиваюсь все время, заключается в том, как правильно освободить ресурсы там, поскольку вы сразу получаете исключение при попытке использовать последовательный порт, который уже используется.

Так как обычно GCЯ должен позаботиться о большей части работы. Я вроде как из идей, что еще попробовать ...

В основном я пробовал 2 вещи, которые (по моей логике) должны делать эту работу.Я использую сеанс связи, поэтому я вызываю методы OpenPort и ClosePort до и после каждого сеанса связи, поэтому порт должен быть закрыт.Также я попытался установить для моего объекта, содержащего порт, значение null впоследствии - но все равно я получаю UnauthorizedAccessExceptions все время - хотя я на 100 процентов уверен, что был вызван метод SerialPort.Close().

Делаете ли выребята, есть ли какие-нибудь лучшие способы освободить порты, чтобы я перестал получать это исключение?

РЕДАКТИРОВАТЬ: Спасибо за ответы, но материал Dispose () не работает - я пробовал это раньше - может быть, яделаю что-то не так, но вот пример того, как выглядит мой код:

На самом деле это очень похоже на то, что предложил Ойвинд, хотя я только добавил IDisposable - но тоже не работает:

это будет мой класс-обёртка:

class clsRS232 : IDisposable
{
  public void clsRS232()
  {
    Serialport port = new Serialport("COM1",9600,Parity.none,8,Stopbits.one);
  }
  public void openPort()
  {
     port.Open();
  }
  public void sendfunc(string str)
  {
    port.Write(str);
  }
  public string readfunc()
  {
    port.ReadTo("\n");
  }

  public void Dispose()
  {
     port.Dispose();
  }

}

Теперь, когда мне нужно общение по rs232, я вызываю новый экземпляр, подобный этому:

   clsRS232 test = new clsRS232;
   test.openport();
   test.sendfunc("test");
   test.Dispose();

Но это ничего не меняет - я всё равно получаюмножество UnauthorizedAccessExceptions - и если другой парень был прав (этот Dispose () класса SerialPort содержит только SerialPort.Close ()) - тогда я думаю, что я ничего не изменил по сравнению с моимпредыдущий подход, где у меня был вызов функции close ();

спасибо за ваши ответы - все еще надеюсь найти решение:)

Ответы [ 3 ]

8 голосов
/ 06 декабря 2010

Поскольку SerialPort реализует IDisposable, вы должны написать свой код следующим образом:

using( SerialPort port = new SerialPort( ... ) ){
  //do what you need with the serial port here
}

Это обеспечит освобождение последовательного порта в конце блока using,и если исключение происходит внутри блока using, в который он был освобожден, поскольку блок using точно такой же, как блок try / finally, он закрывает / удаляет SerialPort внутри блока finally.

РЕДАКТИРОВАТЬ

В соответствии с потребностями ОП SerialPort должен оставаться открытым дольше, чем период метода.

В этом случае я бы обернул всю логику, которая имеетделать с последовательным портом внутри своего класса.В конструкторе класса откройте последовательный порт и напишите методы для выполнения необходимых операций.Затем пусть этот класс сам реализует IDisposable и разместит SerialPort внутри вашего собственного Dispose метода.

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

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

РЕДАКТИРОВАТЬ 2

Ваша текущая реализация выглядит следующим образом:

clsRS232 test = new clsRS232;
test.openport();
test.sendfunc("test");
test.Dispose();

Проблема в том, что если sendfunc вызываетисключение в некотором роде, оно никогда не будет ликвидировано.Во-первых, вы получаете от реализации IDisposable то, что вы можете изменить свой код так:

using( clsRS232 test = new clsRS232 ){
 test.openport();
 test.sendfunc("test");
}

Теперь вам гарантировано, что Dispose будет вызываться для вашего com-порта независимо от того,любых исключений внутри блока using.

3 голосов
/ 19 марта 2015

Я знаю, что это очень старая проблема, но я только что столкнулся с той же проблемой, и это решение сработало для меня, хотя оно немного хакерское. В соответствии с этим потоком почему доступ к com-порту запрещен? проблема связана с ошибкой в ​​SerialPortClass. Я создал класс-обертку, который открывает порт только один раз, и создал класс на время жизни приложения. SerialPort затем удаляется в Dispose класса, но открывается с использованием следующего:

  private SerialPort KickerPort { get; set; }
    .
    .
    .
private bool OpenPort()
        {
            //https://stackoverflow.com/questions/7219653/why-is-access-to-com-port-denied
            //due to a bug in the SerialPort code, the serial port needs time to dispose if we used this recently and then closed
            //therefore the "open" could fail, so put in a loop trying for a few times
            int sleepCount = 0;
            while (!TryOpenPort())
            {
                System.Threading.Thread.Sleep(100);
                sleepCount += 1;
                System.Diagnostics.Debug.Print(sleepCount.ToString());
                if (sleepCount > 50) //5 seconds should be heaps !!!
                {
                    throw new Exception(String.Format("Failed to open kicker USB com port {0}", KickerPort.PortName));
                }
            }
            return true;
        }
     private bool TryOpenPort()
                {
                    if (!KickerPort.IsOpen)
                    {
                        try
                        {
                            KickerPort.Open();
                            return true;
                        }
                        catch (UnauthorizedAccessException)
                        {
                            return false;
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }

                    }
                    return true;
                }

это называется:

 try
            {
                if (OpenPort())
                {
                    //do your thing here !
                }
                return false;
            }
            catch (Exception ex)
            {  
                throw ex;
            }

В своих тестах (я использовал его, чтобы открыть денежный ящик на USB-кикере) я обнаружил, что иногда он открывался впервые, а в другой раз проходил через цикл сна примерно 20 раз, в зависимости от того, как недавно

1 голос
/ 06 декабря 2010

Реализация, предложенная Ойвиндом Бротеном, использует шаблон IDisposable в .NET. В конце блока using вызывается функция Dispose экземпляра SerialPort, которая освобождает связанные неуправляемые ресурсы (т. Е. Последовательный порт)

Вызовите port.Dispose () самостоятельно, когда вы хотите освободить его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...