简体   繁体   English

SerialPort.Close() 问题 - 无法使用任务管理器关闭应用程序!

[英]SerialPort.Close() problem - can't shut down the application with the taskmanager!

This is a major issue - I use a serial port in an application here and I poll the status of the attached device by opening and then closing the port again.这是一个主要问题——我在这里的应用程序中使用串行端口,我通过打开然后再次关闭端口来轮询连接设备的状态。

If the device fails, SOMETIMES the SerialPort.Close() - method NEVER returns and this is really a show stopper.如果设备出现故障,有时 SerialPort.Close() - 方法永远不会返回,这确实是一个表演障碍。

The worst thing is that even shutting down the application using the taskmanager fails, it doesn't work (or it is forbidden, by chance).最糟糕的是,即使使用任务管理器关闭应用程序失败,它也不起作用(或者偶然被禁止)。

The attached device is a POS printer (USB) which simulates COM3, it's an Epson TM-T88IV (a very good model, btw).附加设备是模拟 COM3 的 POS 打印机 (USB),它是爱普生 TM-T88IV(非常好的 model,顺便说一句)。

Does anyone of you have experience with that?你们中有人有这方面的经验吗?

Repeatedly opening and closing the port is not recommended. 不建议反复打开和关闭端口。 Check the Remarks section in the MSDN Library article for SerialPort.Close(). 有关SerialPort.Close(),请查看MSDN Library文章中的“备注”部分。 There's a background thread that needs to shut down before a port can be opened again, that takes time. 有一个后台线程需要在再次打开端口之前关闭,这需要时间。 The amount of time is not predictable. 时间量是不可预测的。

The Close() method can easily deadlock if the DataReceived event handler is currently running. 如果DataReceived事件处理程序当前正在运行,则Close()方法很容易死锁。 The most typical way to get the deadlock is calling Control.Invoke() in the event handler. 获取死锁的最典型方法是在事件处理程序中调用Control.Invoke()。 Make sure you don't use any code in the event handler that blocks or requires a thread context switch. 确保在阻止或需要线程上下文切换的事件处理程序中不使用任何代码。 Using BeginInvoke() is fine. 使用BeginInvoke()很好。

Not being able to kill the program is caused by a problem in the serial port device driver. 无法终止程序是由串行端口设备驱动程序中的问题引起的。 Start Taskmgr.exe, Process tab, View + Select Columns and tick "Handles". 启动Taskmgr.exe,Process选项卡,View + Select Columns并勾选“Handles”。 If after killing the program, you see the Handles column showing 1 then the serial port driver is hanging on to an I/O request that it doesn't complete. 如果在杀死程序后,您看到Handles列显示1,则串行端口驱动程序将挂起到未完成的I / O请求。 The process cannot terminate until all its kernel mode threads are exited. 在退出所有内核模式线程之前,该进程无法终止。

There's little you can do about that particular problem, other than hoping for a driver update or switching to another vendor. 除了希望更新驱动程序或切换到其他供应商之外,您无法对该特定问题做些什么。 Especially USB serial port emulators are notorious for having lousy device drivers. 特别是USB串口仿真器因糟糕的设备驱动程序而臭名昭着。 You get rid of a troublemaker like that by taking it out the parking lot and running it over with your car several times. 你把它从停车场取出并用你的车多次运行就可以摆脱这样的麻烦制造者。

Another typical problem with USB emulators is that they are so easy to disconnect while they are in use. USB仿真器的另一个典型问题是它们在使用时很容易断开连接。 That works about as well as jerking a flash drive out of the socket while Windows is writing to it. 这与Windows正在写入时将闪存驱动器从插槽中抽出一样有效。 It would also be a good way to get the device driver hung .NET versions prior to version 4.0 suffer from a heart attack in a background thread when the device suddenly disappears. 这也是一个让设备驱动程序挂起的好方法当4.0版本之前的.NET版本在后台线程中遭受心脏病发作时,设备会突然消失。 Short from upgrading, a small sign next to the connector that says "Do not disconnect while in use!" 升级之后,连接器旁边的一个小符号显示“在使用时不要断开连接!” is a practical workaround. 是一个实用的解决方法。 They will anyway but get bored with it after a couple of times. 无论如何他们会在几次之后对它感到厌倦。

Fwiw, this is otherwise why the "Safely Remove Hardware" tray icon exists. Fwiw,这就是为什么存在“安全删除硬件”托盘图标的原因。 You'll get a solid "Don't do it!" 你会得到一个坚实的“不要做!” error as long as your program has the port in use. 只要您的程序正在使用该端口,就会出错。 But of course, the operating system is powerless to get users to actually use it. 但是,当然,操作系统无法让用户真正使用它。 Apple has a patent on a technique to make it fail-safe, detecting the user's fingers on the device :) Apple拥有一项技术专利 ,使其具有故障安全性,检测设备上用户的手指:)

Prior to .Net 4.0 a lot could go wrong with USB to SerialPort devices(crash program/system, etc.). 在.Net 4.0之前,USB到SerialPort设备(崩溃程序/系统等)可能出现很多问题。 It was easy to test the errors by pulling the USB adapter with the port active. 通过在端口处于活动状态时拉动USB适配器可以轻松测试错误。

Recently I ran some tests using .Net 4.0 and it is fixed(certainly improved)??? 最近我使用.Net 4.0运行了一些测试,它是固定的(肯定有所改进)??? The test was a simple RX / TX through a USB SerialPort with a loopback, and pull the USB adapter while in use. 测试是通过带有环回的USB SerialPort进行简单的RX / TX,并在使用时拔出USB适配器。 My program did not crash, and I was able to re-open the port! 我的程序没有崩溃,我能够重新打开端口! This is a major improvement. 这是一项重大改进。

While it is sometimes a problem that the SerialPort.Close method deadlocks, that should not prevent Task Manager from killing your process. 虽然有时会出现SerialPort.Close方法死锁的问题,但这不应该阻止任务管理器终止您的进程。 If you can't kill your process, this is almost certainly due to a bug in the USB serial driver. 如果你不能杀死你的进程,这几乎肯定是由于USB串行驱动程序中的一个错误。 Unfortunately, your options are most likely these: 不幸的是,您的选择很可能是:

  • don't poll for device status 不要轮询设备状态
  • get the vendor to fix the bug 让供应商修复错误
  • work around the problem by figuring out a way to poll the device status without accessing the serial port 通过找出一种在不访问串行端口的情况下轮询设备状态的方法来解决问题
  • work around the problem by accessing the device via some other method (perhaps direct USB manipulation) 通过其他方法(可能是直接的USB操作)访问设备来解决问题

Not possible? 不可能?

I've got an idea:Put a flag inside the data recieve event that will close the serialcom from inside! 我有一个想法:在数据接收事件中放置一个标志,从内部关闭serialcom! Simple! 简单!

trying it my self now 现在尝试我自己

如何使用BackGround线程轮询设备,以便它不会阻止您的应用程序退出?

Here's a link with lots of other links to this problem and (potential) solutions: 这是一个链接,其中包含许多此问题和(潜在)解决方案的其他链接:

http://www.vbforums.com/showthread.php?t=558000 http://www.vbforums.com/showthread.php?t=558000

you can use this :你可以使用这个:

private void Form_FormClosing(object sender, FormClosingEventArgs e)
{

    if (_serialPort.IsOpen)
    {
        e.Cancel = true; //cancel the fom closing
        Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit)); //close port in new thread to avoid hang
        CloseDown.Start(); //close port in new thread to avoid hang
    }
}

private void CloseSerialOnExit()
{
    try
    {
        _serialPort.Close(); //close the serial port
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message); //catch any serial port closing error messages
    }
    this.Invoke(new EventHandler(NowClose)); //now close back in the main thread
}

 private void NowClose(object sender, EventArgs e)
{
    this.Close(); //now close the form
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM