我有两个Android设备,我使用操作系统的P2P管理器通过WiFi Direct连接。当设备连接时,我启动AsyncTask以在两个设备之间建立套接字连接。一旦套接字启动并运行(组所有者具有服务器套接字且非组所有者具有客户端套接字),我希望尽可能快地在两个设备之间交换浮动数组,并测量获得带宽估计所需的时间。 / p>
我这样做是让每个设备在建立套接字后立即创建SendThread
和RecvThread
,这些线程分别负责OutputStream
和InputStream
那个设备。他们立即等待锁定,我有一个TestThread
,它按照正确的顺序唤醒它们,以完成他们的沟通。即TestThread
唤醒SendThread
唤醒RecvThread
然后再唤醒TestThread
,然后强制执行命令。
虽然这种方法似乎可以工作几秒钟(我有一个显示数据流的UI),但是这个过程最终会因为两个设备阻塞其recv线程等待输入流上的数据而停顿不前。
我尝试过的事情:
1.使用ObjectStream
发送一个浮动容器以及DataStream
来单独发送浮动
2.在线程池执行程序上使用AsyncTask
来执行交换而不是线程。
上述两者在经过几秒的顺利交换后产生了相同的死锁结果。
我的问题是在这种情况下如何发生僵局?我使用缓冲流并在flush()
进入睡眠状态之前调用SendThread
。睡眠发送线程是否会以某种方式阻止缓冲数据的发送?似乎两个设备都已发送,但都没有收到其他数据。如果我离开设备大约5分钟左右,readFloat()
的冻结呼叫最终完成,但随后又在下一次交换时挂起。
对于需要双向连续通信的P2P多人游戏来说,这必须是常见的操作。
代码如下所示,请注意socketSet
只是封装了套接字(服务器或客户端,具体取决于运行代码的设备)及其流。
测试线程:
public void run()
{
while (runFlag)
{
// Start timer
long timeStart = System.nanoTime();
// Create containers
DataContainer containerArraySend = new DataContainer(10);
DataContainer containerArrayRecv = new DataContainer(10);
// Send and receive with other device //
// Create a new latch
workCounter = new CountDownLatch(containerArraySend.size());
// Set the containers for the respective manager threads
socketSet.sendThread.setDataContainer(containerArraySend);
socketSet.recvThread.setDataContainer(containerArrayRecv);
// Set the new latch
socketSet.recvThread.setLatch(workCounter);
synchronized (socketSets.lockB)
{
// Wake the send thread to start the exchange
socketSets.lockB.notifyAll();
}
// Wait until all the exchanges are complete and woken by recv thread
workCounter.await();
// Log time taken
timeTaken = (double)(System.nanoTime() - timeStart) / 1000000.0;
}
}
发送帖子:
// Send thread
public void run()
{
// Call parent method to set the run flag
super.run();
// Immediately wait on thread creation until test thread releases it
synchronized (socketSet.lockB)
{
socketSet.lockB.wait();
}
// Once released starts executing here
while (runFlag)
{
// Writes to stream and immediate returns (non-blocking)
for (int i = 0; i < dataContainer.size; i++)
{
socketSet.sendStream.writeFloat(dataContainer.dataBuffer[i]);
}
socketSet.sendStream.flush();
synchronized (socketSet.lockC)
{
// Wake recv thread
socketSet.lockC.notifyAll();
}
synchronized (socketSet.lockB)
{
// Sleep send thread until woken by test thread
socketSet.lockB.wait();
}
}
}
Recv Thread:
// Recv thread
public void run()
{
// Immediately lock on thread creation until send thread releases it
synchronized (socketSet.lockC)
{
socketSet.lockC.wait();
}
// Once released starts executing here
while (runFlag)
{
// Blocks until there is data to receive on the stream
for (int i = 0; i < dataContainer.size; i++)
{
dataContainer.dataBuffer[i] = socketSet.recvStream.readFloat();
}
// Count down latch once recv complete (will wake test thread)
latch.countDown();
synchronized (socketSet.lockC)
{
// Recv thread sleeping until woken by send thread
socketSet.lockC.wait();
}
}
}