Как я могу изменить псевдо-код на код NuSMV?
Мой профессор решил дать нам студент-математик код для преобразования в NuSMV, и я не могу найти помощь где-либо еще, и я читаю учебник, он всего 6 страниц и описывает только то, что делает определенное свойство. Модуль main является примером кода NuSMV, и он сказал использовать этот пример формата для написания кода psuedo. Я не знаю, как написать цикл while и установить, что должно быть правдой? а flag1 будет государством, а разворот также будет другим государством?
while(true) do
flag1 := true
while flag2 do
if turn=2
flag1 := false;
wait until turn = 1;
flag1 := true
Critical section
turn := 2
flag1 := false;
1 ответ
It looks like you're trying to model Dekker/Dijkstra's algorithm for mutual exclusion among two processes.
The steps of your interest, based on your question, should only be 1-4. I added some more to provide a more complete picture of what can be achieved with NuSMV.
I used a slightly different version of the same algorithm, though the underlying idea is the same.
IDEA: there exists a methodology for converting pseudo-code into a NuSMV model:
Label the entry and exit point of each statement in your code:
-- void p(iflag, turn, id) { -- l0: while(true) do -- l1: flag := true -- l2: while iflag do -- l3: if turn != id -- l4: flag := false; -- l5: wait until turn = id; -- l6: flag := true -- l7: // Critical section -- l8: turn := 1 - id -- l9: flag := false; -- }
Note that some statements, eg
while iflag do
, might have more than one exit point depending on the value of the guard: ififlag
is true, then the exit point is l3, otherwise the exit point is l7.Create a corresponding module that takes the same inputs and has a state variable which evaluates to the newly introduced labels.
MODULE p(iflag, turn, id) VAR state : { l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, error }; flag : boolean;
Here, notice that i added the special state error. This is only to ensure that during the definition the transition relation for state we are not leaving out any correct transition step. In general, it should be omitted as it does not belong to the original code.
Define the transition relation for state:
ASSIGN init(state) := l0; next(state) := case state = l0 : l1; state = l1 : l2; state = l2 & iflag : l3; state = l2 & !iflag : l7; state = l3 & turn != id : l4; state = l3 & turn = id : l2; state = l4 : l5; state = l5 & turn != id : l5; state = l5 & turn = id : l6; state = l6 : l2; state = l7 : l8; state = l8 : l9; state = l9 : l0; TRUE : error; -- if you match this then the above -- description of transitions are incomplete esac;
Как видите, я просто соединил каждую точку входа с соответствующей точкой выхода. Более того, там, где для данной точки входа определено более одной точки выхода, я также добавил другие условия состояния, чтобы определить, какая строка выполняется следующей.
Добавьте отношение перехода для флага:
init(flag) := FALSE; next(flag) := case state = l1 | state = l6 : TRUE; state = l4 | state = l9 : FALSE; TRUE : flag; esac;
Добавьте некоторые определения, чтобы определить, какие разделы кода выполняет процесс:
DEFINE critical_section := (state = l7); trying_section := (state = l1 | state = l2 | state = l3 | state = l4 | state = l5 | state = l6);
Создайте основной модуль, который создает два экземпляра p:
MODULE main () VAR turn : {0, 1}; p1 : p(p2.flag, turn, 0); p2 : p(p1.flag, turn, 1); ASSIGN init(turn) := 0; next(turn) := case p1.state = l8 : 1; p2.state = l8 : 0; TRUE : turn; esac;
Добавьте некоторые очень типичные свойства взаимного исключения, которые будут проверяться с помощью средства проверки модели:
--*-- PROPERTIES --*-- -- Safety: two processes are never in the critical section at the same time CTLSPEC AG !(p1.critical_section & p2.critical_section); -- Liveness: if a process is in the trying section, then sooner or later -- it will access the critical section. CTLSPEC AG (p1.trying_section -> AF p1.critical_section); -- Absence of Starvation CTLSPEC ! EF AG (p1.trying_section & p2.trying_section); -- Never in Error State CTLSPEC AG !(p1.state = error);
Запустите инструмент
~$ NuSMV -int
и убедитесь, что все свойства проверены:
NuSMV > reset; read_model -i dekker.smv; go; check_property -- specification AG !(p1.critical_section & p2.critical_section) is true -- specification AG (p1.trying_section -> AF p1.critical_section) is true -- specification !(EF (AG (p1.trying_section & p2.trying_section))) is true -- specification AG !(p1.state = error) is true
ЗАМЕТКИ:
Если вы внимательно посмотрите на шаги 1 и 3, некоторые состояния выглядят избыточными. Например, всегда можно свернуть смежные состояния, которые имеют только одну точку входа и выхода. Я оставлю это вам в качестве упражнения.
Обратите внимание, что я использовал синхронную композицию модулей для простоты. На практике проверка будет более значимой, если два процесса будут выполняться асинхронно. Однако для этого потребуется сделать модель более сложной, чем на самом деле требует ваш вопрос, и поэтому она выходит за рамки моего ответа.
Если вы хотите узнать больше о NuSMV, вы можете взглянуть на его документацию или на вторую часть этого курса.