У меня есть два устройства Android, к которым я подключаюсь через WiFi Direct, используя P2P Manager операционной системы.Когда устройство подключается, я запускаю AsyncTask, чтобы установить сокет-соединение между двумя устройствами.Как только сокет запущен и работает (владелец группы имеет сокет сервера, а владелец не группы имеет сокет клиента), я хочу как можно быстрее обмениваться массивами с плавающей запятой между двумя устройствами и измерять время, необходимое для получения оценки пропускной способности.
Я делаю это, когда каждое устройство создает SendThread
и RecvThread
, как только устанавливается сокет с этими потоками, отвечающими за OutputStream
и InputStream
соответственно для этого устройства.Они немедленно ждут на замках, и у меня есть TestThread
, который будит их в правильном порядке, чтобы выполнить свою часть сообщения.то есть TestThread
пробуждает SendThread
, который пробуждает RecvThread
, который затем снова пробуждает TestThread
и, таким образом, один для обеспечения порядка исполнения.
Хотя этот подход, кажется, работает в течение нескольких секунд (у меня естьПользовательский интерфейс, который показывает потоки данных), процесс в конечном итоге останавливается и останавливается, когда оба устройства блокируют свои потоки recv в ожидании данных во входном потоке.
То, что я пробовал:
1.Использование ObjectStream
для отправки контейнера с плавающей точкой, а также DataStream
для индивидуальной отправки float.
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 Тема:
// 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();
}
}
}