Попытка понять алгоритм N-процесса Петерсона

я пытаюсь понять алгоритм N-процесса Петерсона, и я столкнулся с этим вопросом.

вопрос: предположим, что 3 процесса имеют идентификаторы процессов 0, 1 and 2. Эти процессы выполняются одновременно на uni-процессоре и используют алгоритм N-процесса Петерсона для управления выполнением критического раздела. Каждый процесс выполняет следующий псевдо-код:

lock(pid);
<critical section>;
unlock(pid

здесь lock() и unlock() функции как это определено as

lock(for Process i):

/* repeat for all partners */
for (count = 0; count < (NUMPROCS-1); count++) {
    flags[i] = count;
    turn[count] = i;
    "wait until (for all k != i, flags[k]<count) or (turn[count] != i)"
}


Unlock (for Process i):

/* tell everyone we are finished */
flags[i] = -1;

предположим, что состояние системы в любой момент времени определяется <flags[0], flags[1], flags[2], turn[0], turn[1]> значения и идентификатор текущего выполняемого процесса. Далее предположим, что текущее состояние системы <0,0,0,2,-1> С 0 в настоящее время выполняется. Показать один конкретный способ запуска трех процессов до завершения, начиная с этого состояния. При отслеживании параллельного выполнения трех процессов покажите состояние системы на каждом шаг.

мои наблюдения

процессы, запущенные одновременно на uni-процессоре, не могут выполняться на CPU одновременно. Только один из них может выполняться на CPU одновременно. В то время как процесс выполняется на процессоре, он может выполнять любую часть кода.

// NUMPROCS = 3

-- For i = 0

lock(for Process 0):
for (count = 0; count < 2; count++) {
    flags[0] = count;
    turn[count] = 0;
    "wait until (for all k != 0, flags[k]<count) or (turn[count] != 0)"
}


Unlock (for Process 0):
flags[0] = -1;

-- For i = 1

lock(for Process 1):
for (count = 0; count < 2; count++) {
    flags[1] = count;
    turn[count] = 1;
    "wait until (for all k != 1, flags[k]<count) or (turn[count] != 1)"
}


Unlock (for Process 1):
flags[1] = -1;

-- для i = 2

lock(for Process 2):
for (count = 0; count < 2; count++) {
    flags[2] = count;
    turn[count] = 2;
    "wait until (for all k != 2, flags[k]<count) or (turn[count] != 2)"
}


Unlock (for Process 2):
flags[2] = -1;

мой вопрос в том, что С чего начать трассировку кода? Дано, что flags[0]=0, flags[1]=0, flags[2]=0, turn[0]=2, turn[1]=-1 но как это поможет нам, где начать отслеживание кода?

  • если мы начнем перед цикл процесса 0 потом все значения поворота будут установлены на другие значения, отличные от заданных нам.

  • если мы предполагаем, выполнив вопрос значит процесс 0 в это критический раздел тогда цикл for следующего процесса установит превратите ценности во что-то другое.

почему они дают нам значения состояния и как это может помочь нам найти, где начать трассировку кода.

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

спасибо и извините за длинный вопрос.

1 ответов


во-первых, ключевая часть вопроса здесь:

предположим, что состояние системы в любой момент времени определяется <flags[0], flags[1], flags[2], turn[0], turn[1]> значения и идентификатор текущего выполняемого процесса. Далее предположим, что текущее состояние система <0,0,0,2,-1> С 0 в настоящее время выполняется.

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

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

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

Далее, мы можем видеть, что все процессы выполняются один раз и выходят-есть цикл, но мы также можем видеть, что он увеличивает значения flags на каждом повороте, поэтому мы можем предположить, что мы только ударили этот сценарий для значений переменных один раз. Но мы должны пройти через это, чтобы узнать.

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

во время выполнения процесса на CPU он может выполнить любую часть своего кода.

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

таким образом, самый простой способ-просто начать с самого начала и повернуть ручку. Вопрос не говорит об этом, но флаги и поворот обычно инициализируются в -1 так в начало у нас есть:

flags = [ -1, -1, -1 ]; turn = [ -1, -1 ] 

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

for (count = 0; count < (NUMPROCS-1); count++) {

OK, count = 0 для всех процессов, и все они переходят к следующей строке:

flags[i] = count;

Итак:

flags = [ 0, 0, 0 ]; turn = [ -1, -1 ]

пока все хорошо -- следующая строка:

turn[count] = i;

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

flags = [ 0, 0, 0 ]; turn = [ ?, -1 ]

кроме того, что мы делаем, как это в вопросе. Мы можем сделать turn[0] = 2. Так что мы в подходящем состоянии с переменными, мы можем предположить, что процесс 0 находится под контролем и мы знаем, что в этой строке:

"wait until (for all k != i, flags[k]<count) or (turn[count] != i)"

чтобы вы начали, для процесса 0, count = 0 и i = 0 so

"wait until (for all k in {1,2}, flags[k]<0) or (turn[0] != i)"

видно, что or предложение false, поэтому процесс 0 еще раз пройду по кругу. Поэтому будет процесс 1. The for all k предложение не верно ни для кого. Таким образом, процесс 2 будет ждать из-за значения turn[0] -- вы же видите, что это никогда не изменится, поэтому процесс 2 теперь находится в ожидании for all k предложение стать настоящими-на самом деле это ключ к тому, как эта система работает. Если вы последуете логике, чтобы ответить на вопрос, вы увидите, как процессы блокируют друг друга, так что только один когда-либо выполняет критический раздел за раз. Просто продолжайте делать то, что я сделал выше, так как вам нужно найти только один путь, вы можете выполнять строки одновременно, и когда есть потенциальное столкновение, просто выберите значение и идите оттуда.

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

Итак, вернемся к исходному вопросу, есть только несколько мест, где процесс 0 может контролировать это состояние системы. На wait линия, или на for линия, когда количество увеличивается до 1 (после того, как он делает круг) или на линии, где он устанавливает flag[0]. После этого состояние системы меняется. Лучше всего предположить, что самый ранний процесс 1 не заблокирован (пока) и может также изменить состояние.

одна последняя морщинка, для полноты. Есть одно место, где этот процесс можно контролировать и состояние системы может быть такой. И это как раз перед turn[count] = i; линии. В этом сценарии процесс 2 только что установил переменную, и процесс 0 собирается перезаписать ее. Вы можете продолжить отсюда, но это будут процессы 1 и 2, которые идут по кругу. Я включаю это, предвосхищая комментарий об этом, я на самом деле не предлагаю вам используйте это в качестве отправной точки, хотя это вполне допустимым. Вопрос почти наверняка ожидает, что вы начнете с процессов 0 и 1, идущих по циклу, с 2 заблокированными в напряженном ожидании, чтобы увидеть, что произойдет оттуда.

удачи.