Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关闭串口后,阻塞的read不会抛异常中止 #40

Open
yikuo123 opened this issue Nov 3, 2021 · 9 comments
Open

关闭串口后,阻塞的read不会抛异常中止 #40

yikuo123 opened this issue Nov 3, 2021 · 9 comments

Comments

@yikuo123
Copy link

yikuo123 commented Nov 3, 2021

关闭串口时,如果正在 read inputStream,串口和inputStream关闭后,read仍然处于阻塞状态不会终止

@yutils
Copy link

yutils commented Nov 9, 2021

public static byte[] readOnce(InputStream inputStream, long timeOut) throws Exception {
    long startTime = System.currentTimeMillis();
    int count = 0;
    while (count == 0 && System.currentTimeMillis() - startTime < timeOut)
        count = inputStream.available();//获取真正长度
    if (System.currentTimeMillis() - startTime >= timeOut) {
        throw new TimeoutException("读取超时");
    }
    byte[] bytes = new byte[count];
    // 一定要读取count个数据,如果inputStream.read(bytes);可能读不完
    int readCount = 0; // 已经成功读取的字节的个数
    while (readCount < count)
        readCount += inputStream.read(bytes, readCount, count - readCount);
    return bytes;
}

@yutils
Copy link

yutils commented Jan 11, 2022 via email

@yikuo123
Copy link
Author

我这里都会抛异常 read interrupted.应该是你代码写的不对吧。

代码应该是没问题的,无非就是 open、read、close。或许跟环境和串口驱动有关吧,不太确定,我这里确实是有这个问题的。

Android 5以上版本的 FileInputStream 构造函数有个 isFdOwner的参数,通过反射将其改为true就是正常的,修改后,close 时会调用 IoBridge.closeAndSignalBlockedThreads(fd) 就能抛出 Interrupt 异常。

@yutils
Copy link

yutils commented Jan 11, 2022 via email

@Iverlei
Copy link

Iverlei commented Jan 13, 2022

我也复现了你说的情况:关闭串口,仍然还在阻塞read

@licheedev
Copy link
Owner

licheedev commented Jan 13, 2022

@yutils 在每次inputStream.read()之前,先判断一下inputStream.available(),有数据才读一次,例如这样

            while (mRunning) {
                try {
                    if (mInputStream.available() > 0) {
                        len = mInputStream.read(mRecvBuffer);
                        if (len > 0) {
                            receiver.onReceive(validData, mRecvBuffer, 0, len);
                        }
                    } else {
                        // 暂停一点时间,免得一直循环造成CPU占用率过高
                        SystemClockEx.sleep(10);
                    }
                    notifyRunningReceive(mRunning);
                } catch (Exception e) {
                    LogPlus.w(TAG, "Read data failed", e);
                }
            }
            LogPlus.i(TAG, "Read Thread Finished");

可以正常退出读线程

serial.png

实际上这个问题我也遇到过,不止串口,写tcp的socket通信时候也遇到过。
PC端通过测试工具开启TCP服务器,如果手动关闭连接,或者叉掉测试工具,android这边是能正常抛出异常的,但是如果进入控制面板,禁用掉电脑的网卡,android这边就会一直阻塞在read那里,不会抛出异常。所以我都是先判断inputStream.available()后,才会进行读操作,没数据的时候,顺便让线程sleep()一下,否则cpu占用率会很高。

@yikuo123
Copy link
Author

yikuo123 commented Jan 13, 2022

@licheedev

使用 yutils 的方法基本能规避这个问题,当然也确实存在你说的 cpu 空转的情况。

另外,库里面初始化 InputStream 的时候,构造方法如果再加一个参数 isFdOwner,传入 true,就会在关闭时执行 IoBridge.closeAndSignalBlockedThreads(fd),这会让 read 抛出异常从而终止。
不过低版本Android并没有这个构造方法,也不清楚有没有其它副作用。

mFileInputStream = new FileInputStream(mFd, true);

@Iverlei
Copy link

Iverlei commented Jan 14, 2022

我上面的方法都没不适用我这个应用,我现在的做法是,用一个全局的viewmodel 一直做阻塞读,读到就写到livedata中,然后要用的时候就在具体的UI界面observe全局的livedata。

@coolxiao
Copy link

coolxiao commented May 8, 2023

InputStream.available() 始终为0 但实际有数据

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants