Блокировка с помощью сокетов Java, блокировок и потоков - PullRequest
0 голосов
/ 06 июня 2018

У меня есть два устройства 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();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...