栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

UsbRequest.queue导致Android 3.1应用程序崩溃

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

UsbRequest.queue导致Android 3.1应用程序崩溃

好的,我取得了一些突破,发现了两个问题:

  • 的调用
    _currentOutputRequest.queue(_outputBuffer, _maxPacketSize);
    传递了整个缓冲区容量
    _maxPacketSize
    ,该容量的常量值为64(字节)。显然,这仅适用于批量读取,最多可以读取64个字节。批量发送请求需要指定要发送的确切字节数。
  • _currentOutputRequest.queue()
    _connection.requestWait()
    方法调用似乎不是线程安全的,特别是在执行
    UsbDeviceConnection
    (其是所述类型的
    _connection
    )。我怀疑UsbRequest
    _currentOutputRequest
    在排队发送请求时在内部使用UsbConnection对象。

我如何解决这个问题:

的呼叫

queue()
已更改为:

_currentOutputRequest.queue(_outputBuffer, _outputBuffer.position());

对于第二个问题,该

queue()
语句已经在
synchronized
使用该
_outputLock
对象的块内发生。在
Run()
阅读器线程的方法中,我还必须使用以下命令将调用包装到
requestWait()
一个
synchronized
块中
outputLock

UsbRequest request = null;synchronized(_outputLock){    // requestWait() and request.queue() appear not to be thread-safe.    request = _connection.requestWait();}

鉴于这种情况发生在

while
循环中并
requestWait
阻塞了线程,我发现的一个主要问题是,当试图将发送请求排队时,锁会导致饥饿。结果是,当应用程序及时接收传入的MIDI数据并对其进行操作时,输出的MIDI事件会大大延迟。

作为此问题的部分解决方案,我

yield
while
循环结束前插入了一条语句以使UI线程保持畅通。(UI线程被暂时用作注释事件,因为它是通过按下按钮触发的;它最终将使用单独的播放线程。)因此,它更好,但并不完美,因为在第一次输出注释之前还有相当长的延迟已发送。

更好的解决方案:

为了解决对异步读取和写入的互锁的需求,异步

queue()
requestWait()
方法仅用于读取操作,这些操作保留在单独的“读取器”线程上。因此,该
synchronized
块是不必要的,因此可以将该段缩减为以下内容:

UsbRequest request = _connection.requestWait();

至于写/发送操作,其核心已移至用于执行同步

bulkTransfer()
语句的单独线程:

    private class MidiSender extends Thread    {        private boolean _raiseStop = false;        private Object _sendLock = new Object();        private linkedList<ByteBuffer> _outputQueue = new linkedList<ByteBuffer>();        public void queue(ByteBuffer buffer)        { synchronized(_sendLock) {     _outputQueue.add(buffer);     // Thread will most likely be paused (to save CPU); need to wake it     _sendLock.notify(); }        }        public void raiseStop()        { synchronized (this) {     _raiseStop = true; } //Thread may be blocked waiting for a send synchronized(_sendLock) {     _sendLock.notify(); }        }        public void run()        { while (true) {     synchronized (this)     {         if (_raiseStop)   return;     }     ByteBuffer currentBuffer = null;     synchronized(_sendLock)     {         if(!_outputQueue.isEmpty())  currentBuffer =_outputQueue.removeFirst();      }     while(currentBuffer != null)     {         // Here's the synchronous equivalent (timeout is a reasonable 0.1s):         int transferred = _connection.bulkTransfer(_outPort, currentBuffer.array(), currentBuffer.position(), 100);         if(transferred < 0)  Log.w(_tag, "Failed to send MIDI packet");         //Process any remaining packets on the queue         synchronized(_sendLock)         {  if(!_outputQueue.isEmpty())      currentBuffer =_outputQueue.removeFirst();  else      currentBuffer = null;         }     }     synchronized(_sendLock)     {         try         {  //Sleep; save unnecessary processing  _sendLock.wait();         }         catch(InterruptedException e)         {  //Don't care about being interrupted         }     } }        }    }

起初,我担心异步代码与上述代码冲突(因为它们共享相同的

UsbDeviceConnection
),但这似乎不是问题,因为它们使用的是完全不同的
UsbEndpoint
实例。

好消息是,在我弹奏键盘的同时发送笔记时,应用程序运行更流畅且不会崩溃。

因此,一般而言(对于在单独端点上的双向USB通信),异步方法似乎最适合于读/输入操作,在这种情况下,我们无需担心定义轮询行为(无论这是否在内部发生)
),而同步

bulkTransfer()
方法可以更好地服务于输出/发送操作。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/515476.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号