2016-05-30 4 views
3

Я пытаюсь синхронизировать 3 потока. Каждый из них обрабатывает гусеницу, которая движется по ее собственному пути. км. К сожалению, их дорожки пересечены следующим образом: imageТемы - Разблокировка блокировки с использованием флагов и попытка/наконец

Для этой цели я пользуюсь замками. Есть два раздела, где разделены блоки: горизонтальные и вертикальные (я назвал его выше и ниже). Проблема в том, что поток в одной точке хочет быть в двух разделяемых разделах одновременно.

Мой вопрос:

Могу ли я разблокировать замок внутри TRY/наконец, п, используя флаг?

Я имею в виду, что когда нить разблокирует блокировку внутри предложения try/finally, устанавливается флаг, и в предложении finally он проверяет, установлен ли флаг, а затем не разблокируется второй раз. Я думаю, что это безопасное решение, но, возможно, я ошибаюсь.

Есть ли другой способ синхронизации потоков?

Это мой код: (Это почти работает)

public void moveForward() throws InterruptedException { 
    redIsUpofAbove(); 
    int choose= 0; 
    if (Route.critcalSectionAbove.contains(head)) 
     choose= 1; 
    if (Route.critcalSectionBelow.contains(head)) 
     choose= 2; 

    switch (choose) { 
    case 1: { 
     boolean flag = true; 
     System.err.println(name + " Lock above"); 
     synchronization.aboveLock.lock(); 
     try { 

      takeNextGrid(); 
      Thread.sleep(sleepValue); 
      while (isInAboveCriticalSection()) { 
       takeNextGrid(); 
       Thread.sleep(sleepValue); 
       if (isInBelowCriticalSection()) {// Caterpillar is on two 
                // shared sections 
        System.out.println(name + " Lock below"); 
        if (!synchronization.belowLock.tryLock()) { 

         synchronization.aboveLock.unlock(); 
         System.out.println(name + " Unlock above"); 
         synchronization.belowLock.lock(); 
         flag = false; 
        } 
        try { 
         while (isInBelowCriticalSection()) { 
          takeNextGrid(); 
          if (!isInAboveCriticalSection() && flag) { 
           synchronization.aboveLock.unlock(); 
           flag = false; 
           System.out.println(name + " Unlock above"); 
          } 
          Thread.sleep(sleepValue); 
         } 
        } catch (Exception e) { 
        } finally { 
         synchronization.belowLock.unlock(); 
         System.err.println(name + "Unlock belovelock"); 
        } 
       } 
      } 
     } catch (Exception e) { 
     } finally { 
      if (flag) { 
       synchronization.aboveLock.unlock(); 
       System.out.println(name + " unlock above"); 
      } 
     } 

     break; 
    } 
    case 2: { 
     boolean flag = true; 
     System.err.println(name + " Lock below"); 
     synchronization.belowLock.lock(); 
     try { 

      takeNextGrid(); 
      Thread.sleep(sleepValue); 
      while (isInBelowCriticalSection()) { 
       takeNextGrid(); 
       Thread.sleep(sleepValue); 
       if (isInAboveCriticalSection()) { 
        if (!synchronization.aboveLock.tryLock() && flag) { 
         synchronization.belowLock.unlock(); 
         System.out.println(name + " Unlock below"); 
         synchronization.aboveLock.lock(); 
         flag = false; 
        } 
        try { 
         System.out.println(name + " Lock above"); 
         while (isInAboveCriticalSection()) { 
          takeNextGrid(); 
          if (!isInBelowCriticalSection() && flag == true) { 
           synchronization.belowLock.unlock(); 
           flag = false; 
           System.out.println(name + " Lock below"); 
          } 
          Thread.sleep(sleepValue); 
         } 
        } catch (Exception e) { 

        } finally { 
         synchronization.aboveLock.unlock(); 
         System.err.println(name + "Lock abovelock"); 
        } 

       } 
      } 
     } catch (Exception e) { 

     } finally { 
      if (flag) { 
       synchronization.belowLock.unlock(); 
       System.out.println("Opuszczam belowLock"); 
      } 
     } 

     break; 
    } 
    default: { 
     takeNextGrid(); 
     break; 
    } 
    } 

} 

И последний вопрос:

Есть ли способ, чтобы установить приоритет, чтобы проснуться, на нитях, которые ждут на заблокированный замок?

ответ

3

Могу ли я разблокировать блокировку внутри предложения try/finally с использованием флага?

Предполагая, что вы не получите InterruptException между lock() вызова и когда вы установите флаг, то это должно работать правильно; однако, я не думаю, что это имеет смысл в данном контексте.

Если вы получаете исключение, что происходит с гусеницей? Он исчезает? Если он все еще сидит в одном и том же месте на пути, даже после исключение бросается, то оно все еще занимает этот участок пути; поэтому не имеет смысла выпускать замок.


Есть ли другой способ синхронизации потоков?

Есть определенно другие синхронизации механизмов, которые вы могли бы попробовать (атомарные, монитор замки и т.д.), но это не похоже на производительность важных приложений, так что я просто хотел бы использовать все, что имеет больше смысла тебе. Если замки имеют смысл, используйте блокировки.

Теперь, если вы спрашиваете, если есть другой способ для синхронизации (то есть, другая стратегия использовать для взаимного исключения на ваших путях), то у меня есть предложение для этого:

caterpillar tracks with 4 critical sections

Ваше текущее решение имеет очевидную проблему взаимоблокировки.Поскольку секции below и above приобретаются отдельно, синяя гусеница (G2, «Синяя») может приобретать нижнюю секцию и перемещаться, и в то же время красная гусеница (G1, «Красный») может приобретать верхнюю секцию и двигаться дальше. Теперь ни один из гусениц не может завершить свой путь - они зашли в тупик (G1 не сможет продвинуться в нижнюю секцию, а G2 не сможет продвинуться в верхнюю часть).

Разделив путь на более критические разделы (как показано на моем изображении) и получив несколько разделов при переходе в критические разделы, вы можете избежать этой ситуации взаимоблокировки.

Пока вы гарантируете, что в «критической Т» (т. Е. Объединении всех 4 критических областей) не более 2 гусениц, то вы всегда можете избежать тупиковой ситуации. Вы можете сделать это, создав counting semaphore с двумя разрешениями. Вы acquire() перед захватом блокировки для первой критической области пути, и release() когда-то после ухода из этого региона. Например, для красного цвета, то последовательность будет:

  1. acquire() на sempahore
  2. lock() Выше и продвижение через нее
  3. lock() Ниже налево
  4. release() на семафора
  5. Продолжите в центр, а затем внизу слева
  6. После того, как красные хвосты покидают Центр, unlock() Выше
  7. После того, как хвост Ред листы ниже слева, unlock() Ниже налево
  8. Продолжите через некритичную область ...

Обратите внимание, что мы не должны явно блокировать центр, поскольку он неявно защищен семафор и другие замки.

Существуют, очевидно, другие методы, которые можно использовать для обеспечения наличия только 2 гусениц в «критическом Т», но семафор казался самым простым способом сделать это.

Это решение позволяет избежать тупиковой ситуации следующим образом:

  • Если Красный находится в Наверху, и синий в ниже справа, затем синие блоки, пока он не может получить выше, прежде чем перейти в центр, что позволяет Red, чтобы выйти из критического регион первый.
  • Если синий находится внизу справа, а зеленый находится внизу слева, тогда зеленые блокируют до тех пор, пока он не сможет получить «Прямо перед собой», прежде чем перейти в центр, что позволит Blue выйти из критической области в первую очередь.
  • Если зеленый находится внизу слева, а красный находится выше, то красный блокируется до тех пор, пока он не сможет захватить нижнее левое перед тем, как перейти в центр, чтобы Green мог сначала выйти из критической области.

Все остальные возможные конфигурации также позволят избежать взаимоблокировки - это всего лишь три наиболее интересных случая.


Есть ли способ, чтобы установить приоритет, чтобы проснуться, на нитях, которые ждут на заблокированном замке?

Я не знаю никаких инструментов в библиотеке Java, которые фактически предоставили бы вам приоритетные гарантии, подобные этому. Вам нужно будет либо найти стороннюю библиотеку, либо сделать это самостоятельно.

Простой способ сделать это будет только не использовать отдельные темы для ваших гусениц. Вы можете использовать всю свою гусеничную логику с помощью одного потока - нет причин, по которым вам нужна одна нить для каждой гусеницы. Если бы у вас была вся логика в одном потоке, тогда порядок, в котором вы обрабатывали гусениц, дал бы вам неявный порядок приоритетов.

+0

Спасибо за ваш ответ, это было очень полезно и полезно. Я думал о ваших советах, и я пришел к выводу, что это правильный алгоритм. Я реализовал его и ... его работу! Концепция этого упражнения состояла в том, чтобы использовать отдельные потоки и синхронизировать их. Я был очень близко, но семафоры на замках оказались чем-то необходимым. Еще раз спасибо. – TomaszGrzybowski

0

Алгоритм DaoWen хорошо работает. Это код для Red Caterpillar, другие Caterpillars работают по адресу тот же принцип с небольшими изменениями. Я разделил путь на три критические секции: выше, слева внизу, справа внизу. Центр-регион помогает определить, когда гусеница покинула критический участок, а затем разблокирует блок. Семафоры гарантировали, что максимально два потока могут запрашивать ввод в критические разделы. Флаги полезны для разблокировки блока перед концом метода и обеспечения того, что блоки не разблокированы только один раз.

public final ReentrantLock aboveLock = new ReentrantLock(true); 
public final ReentrantLock LeftBelowLock = new ReentrantLock(true); 
public final ReentrantLock RightBelowLock = new ReentrantLock(true); 
public final Semaphore semaphore = new Semaphore(2); //counting semaphore 

private void movingRed() throws InterruptedException { 
    while (true) { 
     if (Route.critcalSectionAbove.contains(head)) { 
      synchronization.semaphore.acquireUninterruptibly(); 
      synchronization.aboveLock.lock(); 
      isAboveLock = true; 
      synchronization.LeftBelowLock.lock(); 
      isBelowLeftLock = true; 
      synchronization.semaphore.release(); 
      try { 
       while (!ifTailLeftCenter()) { // advance Critical-region 
               // until tail crosses center 
        takeNextGrid(); 
        Thread.sleep(sleepValue); 
       } 
       // caterpillar's tail left Center section 
       isAboveLock = false; 
       synchronization.aboveLock.unlock(); // unclocking above 
       while (isInBelowCriticalSectionLeft()) { // advance until 
                  // tail belong 
                  // to Left-Below 
        takeNextGrid(); 
        Thread.sleep(sleepValue); 
       } 
       // caterpillar's tail left LeftBelow section 
       isBelowLeftLock = false; 
       synchronization.LeftBelowLock.unlock(); 
      } catch (Exception e) { 
      } finally { 
       if (isAboveLock) 
        synchronization.aboveLock.unlock(); // in case exception 
                 // was throw before 
                 // unlock any lock 
       if (isBelowLeftLock) 
        synchronization.LeftBelowLock.unlock(); 
      } 
     } 
     // caterpillar moving through non-critical region 
     takeNextGrid(); 
     Thread.sleep(sleepValue); 
    } 
} 

Благодарим за помощь.