Аксиоматический метод верификации на основе декомпозиции состояний в методе RGSep

УДК 004.451.2

А.С. Прокопенко, А.Г. Тормасов

АКСИОМАТИЧЕСКИЙ МЕТОД ВЕРИФИКАЦИИ НА ОСНОВЕ ДЕКОМПОЗИЦИИ СОСТОЯНИЙ В МЕТОДЕ RGSEP

Проверка соответствия выполнения параллельных программ заданной спецификации осложнена тем, что порядок, в котором будут выполнены инструкции разных потоков, заранее непредсказуем и необходимо рассмотреть всевозможные варианты выполнения программ. Часто спецификация системы может быть разбита на отдельные свойства, описывающие поведение небольших фрагментов системы. В таком случае применение стратегии проверки каждого локального свойства может позволить избежать проблемы «комбинаторного взрыва» в пространстве состояний системы - значительного роста объема проверок даже при небольшом усложнении комплекса программ. При верификации нужно также учитывать, что программные модули создаются для исполнения в различном окружении. Существующие методы формальной верификации, в частности, дедуктивные методы на основе Rely/ Guarantee (R/G) [2], предполагают, что верифицированные в одной системе фрагменты при переносе в другую систему часто требуют новой верификации в условиях изменившегося окружения. Повторную верификацию можно упростить, если изначально как можно точнее локализовать и исследовать влияние окружения на фрагменты программы.

В статье предлагается метод формальный верификации на основе дедуктивного метода композиционной верификации RGSep [1], позволяющий точнее локализовать и исследовать влияние окружения на фрагмент программы за счет введения правил скрытия областей памяти, рассмотрения устойчивости слабейших предусловий и сильнейших постусловий под воздействием окружения.

Обзор метода верификации Rely-Guarantee

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

Композиционный метод дедуктивной верификации программ на общей памяти R/G зарекомендовал себя как качественный метод верификации параллельных программ по заданным критериям. Данный метод позволяет провести верификацию потоков параллельной программы по отдельности. В этом методе для каждого потока выполнение параллельной программы представлено двумя отношениями: Rely и Guarantee, где первое описывает изменение состояний, выполненное потоком, а второе описывает выполнение всех других потоков - внешней среды (окружения). Поскольку выполнение потока зависит от поведения среды, пользователь записывает ряд допущений R. о предполагаемом выполнении среды. Также пользователь формулирует ряд допущений G . о выполнении потока. Спецификация каждого фрагмента кода С потока Т. в окружении E. задается четверкой (p, R, G, q.). Высказывания p , q . называются пред- и постусловиями. Предусловие p описывает накладываемее на начальное состояние ограничение, постусловие q описывает ограничение, накладываемое на финальное состояние потока. Выполнение потока считается правильным в смысле частичной корректности, если предусловие удовлетворяет p , изменения общих состояний выполняются в соответствии с R , выполнение кода потока удовлетворяет G , и если поток завершает работу, то постусловие удовлетворяет q .

Обычно память в R/G методе устроена следующим образом: она разделена на ячейки, каждый из потоков имеет доступ ко всем ячейкам памяти. Каждая ячейка имеет идентификатор, представляющий собой слово из латинских букв и цифр и начинающийся с буквы. Ячейки содержат целые числа (запись типа Stores : Vars ^ Values означает, что определена функция Stores, отображающая множество Vars в Values, т. е. каждой ячейке памяти приписывает число):

Values = {..., -2,-1,0,1,...}; Vars = {x, y,...};

Stores : Vars ^ Values.

Основой для логики выводов правильных программ служат аксиомы и правила вывода. Параллельное выполнение потоков Cx и C2 обозначается как Cj||C2. Запись о том, что выполнение потока Cj удовлетворяет спецификации (p,R,G,q) записывается как CJsatRG(p,R,G,q). Правило корректного выполнения двух потоков в окружении требует, чтобы выполнение каждого из двух потоков удовлетворяло допущению о выполнении и среды, и потоков. Такая конъюнкция допущений записывается как R v Gt. Требование выполнения постусловий и первого, и второго потока записывается как qj л q2. Правило корректного выполнения двух параллельных потоков С и С2 записывается как

C^atwipXR v G2),Gvq{) C2satRG

Несмотря на ряд позитивных свойств, метод R/G имеет существенные недостатки, в частности, следующие.

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

2. Необходимость спецификации всей памяти, даже если рассматриваемая часть системы имеет доступ только к части памяти.

3. Сложность предоставления доступа другим потокам к динамически создаваемым ячейкам памяти.

4. В рамках метода R/G нет возможности описать программу, в которой некоторые потоки имеют совместно используемые области памяти, скрытые от других потоков.

5. Параллельная композиция потоков статична: нет возможности верифицировать программы с динамически создаваемыми и завершаемыми потоками (команды «fork» и «join»).

6. Метод R/G неприменим для верификации свойств живучести (или живости - liveness properties). Иначе говоря, живость - это те свойства программ, которые утверждают, что нечто изначально задуманное произойдет при любом развитии внешних событий и на любом этапе работы собственно программы.

Первые пять из приведенных недостатков являются основными причинами, побудившими Джонса в 2003 г. написать статью [10], призывающую работать над улучшением декомпозицон-ности (т. е. разбиения модели памяти на части,

исследования взаимного влияния потоков друг на друга в условиях новой модели, исследования переносимости верифицированных фрагментов в другие окружения) R/G метода. Успехи на этом поприще будут способствовать переносимости фрагментов программ, верифицированных в одном окружении, в другие окружения с меньшими трудозатратами.

Обзор сепарационной логики

Сепарационная логика была создана как расширение логики Хоара, позволяющее анализировать программы с указателями и динамически выделяемыми структурами. Ключевым элементом этой логики является операция сепарационной конъюнкции (separating conjunctions), используемая для определения разрозненных частей памяти. Запись сепарационной конъюнкции p*p' обозначает возможность разбития программных состояний на две части. Первая часть характеризуется высказываниемp, вторая -p'.

Модель памяти в сепарационной логике устроена, например, следующим образом [6]:

Values = {...,-2,-1,0,1,...}; Vars = {*, ....};

Locations — {1, 2,....}; В — {true, false}', Heap = Locations —>fin Values-, Stores - Vars —> fln Values', Bool = Vars ->ftn В; X = Stores X HeapX Bool.

Запись [x] означает содержание ячейки по адресу x. Сами программные состояния характеризуются через утверждения, описывающие состояние памяти (формулы состояния памяти).

Если X - пространство программных состояний, B={true,false}, тогда высказыванием (утверждением) p над пространством состояний называют предикат вида р = {а I а: X —> В} .

В сепарационной логике высказывания задаются следующим образом:

^ q I p * q I p-q |...

Здесь emp введено для обозначения пустой кучи (Heap), e ^ e' описывает состояние, в котором куча состоит из одной выделенной ячейки c адресом e с содержанием e'Запись сепарационной конъюнкцииp*q означает возможность разбития кучи на две части: первая часть кучи характеризуется высказыванием p, вторая - q. Сепарационное

вычитание (septraction) обозначается как p - q и означает, что куча, характеризующаяся утверждением q, может быть разбита на две части, одна из которых описывается утверждением p. Отношение выполнимости (t,h,i)\=p означает, что в состоянии (t, h,i) £ S, t £ Stores, h £ Heap, i £ Bool утверждение p истинно. Формальная запись се-парационной конъюнкции и сепарационного вычитания:

(t,h) \= (p * q) 3h.j,h2h1 1 h2 =

= h л (hi \= p) л (h2 \= q) ; (t, h) \= (p-q) 3h.j, h2.h1 1 h =

= h2л (hi \= p) л (h2 \= q).

В отличие от метода R/G в сепарационной логике для параллельных программ на общей памяти (Concurrent Séparation Logic, CSL) гарантией независимости параллельного выполнения потоков является требование доступа этих потоков к различным частям общей памяти. Обращение двух потоков к различным частям памяти подчеркивается записью сепарационной конъюнкции пред- и постусловий. Отношение выводимости формул обозначается как \-. Правило корректного выполнения имеет вид:

l-{Pi}Ci{gi} \-{р2}С2{д2} \-{p1*p2}ClUC2{q1*q2} '

В логике CSL подразумевается взаимодействие потоков через общую память только при строгом контроле отсутствия состояния конкурентного доступа к памяти (ситуации, когда несколько потоков пытаются одновременно получить доступ к одной и той же ячейке памяти). Это достигается путем определения точного инварианта (précisé invariant), который определяет условия монопольного доступа к общим ячейкам памяти.

Комбинирование R/G и CSL

Применение R/G метода верификации параллельных программ осложнено тем, что модель состояний представлена одним пулом памяти. В то же время CSL обладает мощным аппаратом для разделения памяти на части. Однако верификация CSL логикой осложнена выразительной способностью инвариантов, делающих непригодным CSL логику для верификации параллельных

программ при необходимом уровне атомарности команд типа чтение/запись. Исследователями выполнен большой объем работы для объединения сильных сторон обоих подходов в единые методы верификации: SAGL [3], RGSep и LRG [8]. Эти подходы различаются как по технической реализации метода (уровню абстрактности задания команд используемого языка программирования типа Си, грамматики высказываний, модели программных состояний, правил вывода), так и по выразительной силе (возможности расширения этих методов для верификации свойств живости, сокрытию ячеек памяти одних потоков от других ит.д.).

Метод RGSep и SAGL

В методе RGSep и SAGL ячейки памяти разделены на общие и на локальные. Состояние о каждого потока включает общие состояния s и локальные l, доступные только этому потоку. Спецификация фрагмента C потока программы задается четверкой ((p,r), R, G,(q,r')), где p и q -пред- и постусловия, определяющие локальные состояния потока, r и r'- спецификация общих частей. В RGSep и SAGL правило параллельного отличается от соответствующего правила R/G тем, что отображает разделение памяти потока на общую память и локальную необходимостью спецификаций этих частей отдельными предикатами:

RvG2-,G1\-{(p1,r)}Cl{(q1,r1)}

RvGi,G2\-{(p2,r)]C2{(q2,r2)}_

ВД V G2\-[(Pl *p2,r] Q IIC2 {(Л * р2,Г1 A r2)}.

В методе SAGL используется язык программирования, заданный грамматикой типа грамматики ассемблерного языка программирования для RISC-архитектуры с примитивами блокирования/ разблокирования (lock/unlock), это затрудняет использование метода на практике по чисто техническим соображениям. В методе RGSep используется язык программирования типа Си, что делает этот метод более удобным в применении.

Метод RGSep допускает деление общей памяти на несколько регионов rv ..., r , каждый из которых специфицируется парой (R(r),G(r)), любой из потоков системы может иметь доступ к каждой из этих областей памяти. Правило выполнения фрагмента кода C во взаимоисключающем режиме имеет вид [12]:

|~{(Р"*Р'\ * • * Рп)}аЮтк{С}{(д"* д[ *... * д'п )} Уге{1.....п}: ДяЦд.ад) Б1аЬ(д,,Я(г1)) ру

У) с ОД

Я,С\-{(р', р? *... * рг/)}сИот1с{СШ,Ч? * * д'*)}

где запись Stab(р , R(г)) означает устойчивость предиката под действием окружения, специфицированным Я(г.) (формальное определение будет дано ниже).

Показано, что RGSep метод применим для верификации некоторых свойство живости [5], программ с динамическим созданием/завершением потоков [9]. Существуют автоматизированные реализации метода RGSep и т. д. Но не доказано, что метод обладает достаточной выразительной силой для верификации программ, в которых некоторые потоки имеют области памяти, скрытые от других, что ограничивает модульность.

Метод LRG

Несмотря на внешнюю схожесть с методами RGSep и SAGL, метод LRG является отдельным методом на основе ИЮ и CSL. Метод LRG создавался с целью дедуктивной верификации программ, в которых некоторые потоки могут иметь области памяти, скрытые от других. Отличия этого метода от RGSep заключаются в логическом, а не в фактическом разделении на локальные и общие ячейки памяти потоков, в способе зада-

ния высказываний, в контроле за устойчивостью высказываний под воздействием окружения, в правилах вывода. Как и в CSL, разделение на области памяти происходит при задании строгих инвариантов I (соответствующая запись имеет вид I > [Я,О] и читается как «действия окружения и потока защищены точным инвариантом I»). Спецификация фрагмента кода потока определяется пятеркой (р*г, R, G, I, г*г'). Также метод отличается от RGsep и SAGL наличием правила сокрытия части общих регионов памяти от некоторых потоков:

Я * Я'; О * О'; I * 1'|-[р ]С[д ] I > [Я, О] Я, 0,1\-[р]С{д ]

Правило параллельного исполнения имеет вид:

Я и 02;О!;I-{р * г]С1[д1 * г '] I > [Я,О] Я и О;;О2;I-{Р2* г]С2[д2* г '] г и гх и г2 ^ I Я°1 и О2;I|-{Р1 * Р2 * г ] С1 | С2 {Р1 * Р2 * (г1 А г2)]

Правило выполнения фрагмента кода С во взаимоисключающем режиме имеет вид:

Ри8=>/ 1>{Я,С} Sta({p,q},R* М) ^-»(^еС? Я; в; /|-{ р \atomic {С} {д}

Главным недостатком LRG является сложность задания точных инвариантов, причем, непонятно, возможно ли использовать подход из CSL, когда инварианты ослабляются до задания интуитивных высказываний [8]; также до сих пор не доказано и не опровергнуто, что метод применим для доказательства свойств живости; не исследована устойчивость слабейших предусловий и сильнейших постусловий под влиянием окружения (положительные результаты исследования в этом направлении могли бы снизить объем работы по верификации фрагментов программы, перенесенных из окружения, в котором они уже были верифицированы).

Цель работы

В целях улучшения применимости метода ИЮ к верификации многопотоковых программ созданы три метода дедуктивной верификации:

SAGL, RGSep и LRG. Эти методы различаются как по математической модели, так и по типам программ, которые они способны верифицировать. Наиболее активно развиваются два: RGSep и LRG. Единственным серьезным преимуществом метода LRG перед RGSep является возможность верификации программ, в которых одни потоки имеют совместно используемые области данных, скрытые от других потоков. В прочих компонентах метод RGSep более проработан. Это выражается в возможности верификации методом RGSep свойств живости; требуется меньше усилий для верификации компонентов системы в различных окружениях за счет исследования устойчивости слабейших предусловий, слабейших постусловий под влиянием окружения; определенные шаги метода автоматизированы. Сейчас, например, если необходимо проверить дедуктивным методом библиотечную функцию, при выполнении

создающую несколько потоков, на отсутствие гонок, термируемость, то надо использовать и RGSep, и LRG, что фактически означает проведение двойной работы по спецификации, формальному доказательству (выводу последовательности формул).

Решение проблемы расширения применимости метода RGSep для верификации программ, в которых одни потоки имеют общие регионы памяти, скрытые от других потоков позволит верифицировать разные свойства программ единым расширенным методом RGSep там, где ранее приходилось использовать сразу два метода - RGSep и LRG.

Для этого необходимо решить следующие задачи:

внести изменения в модель состояний;

ввести новое правило сокрытия ресурсов, позволяющее скрывать общие регионы памяти некоторых потоков от действий других;

внести необходимые поправки в другие правила RGSep логики;

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

Модель состояний программы

При построении модели параллельных программ необходимо формально представить состояния и переходы между состояниями.

В нашем расширении метода RGSep модель памяти построена на основе модели памяти се-парационной логики, указанной выше в обзоре сепарационной логики.

Каждый поток имеет эксклюзивный доступ к локальной памяти Ь и дос^п к ячейкам! общей памяти S. Состояние потока о записывается как о = (Iе X2 ,1 е Ь^ е 5". В нашей модели общей памяти могут существовать области (регионы) памяти г1,. гп с 5, V/, 7 : г п г^ = 0;

п

V/ ,] \ 7,1 < /,] < п ; = 5. К некоторым ре/ = 1

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

Синтаксис языка программирования

Будем рассматривать параллельные программы, каждая из которых представляет собой последовательность из инициализирующих команд и набора одновременно исполняющихся потоков С0;(С1||.||Сп). Каждый поток состоит из операторов.

Определим синтаксис используемого языка программирования типа Си следующим образом:

команды: C := skip | х = E | х = [E] | [E] = E | C; C | if B then{C} else {C}| while B do {C} | х = new() | | delete(E) ;

целочисленные выражения: E := х | n | E iop E;

логические выражения: B := b | E bop E .

Вспомогательные определения: n e Z - множество целых чисел; b e В = {true, false} - множество логических значений; iop e lop = {+,-,[],...} -конечное множество целочисленных бинарных операций; bop eBop = {= ,<,>,..} - конечное множество логических бинарных операций. Запись [x] означает содержание ячейки по адресу x. Оператор skip (пустой оператор) не меняет состояния программы.

Синтаксис и семантика логики высказываний

Поскольку в нашей модели мы представили состояния как разбиение на регионы, то высказывания характеризуют сразу всё состояние. Тут можно специфицировать каждое состояние посредством высказываний для каждой региона памяти, но вместо этого воспользуемся грамматикой высказываний из RGSep. Тогда, пусть запись p - утверждение относительно общих частей, а p~- локальных. Синтаксис логики высказываний: p, q := p | true | false | emp | e =

Отношение |= выполнимости формулы высказывания в состоянии (s,l) определяется по индукции (оператор l=SepL - означает выполнимость в сепарационной логике): (s,l)\=P**l±SepLP

сs,l) 1= р <=> {I = null) Л

(5,0 1= рх*р2 <=> = 1г -L l2) A(h>s\=sePL Pi)A

A

(s,l) 1= р1 Л р2 О (7,, s \=SepL Pj) A (l2,s\=SepL р2) (,s,l) оЗ/р/^ = i, XOAapShj^, р)л

A

Взаимное влияние потоков друг на друга

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

При исполнении параллельной программы часть потоков может обращаться к общим ячейкам памяти. Обращение к ячейкам происходит посредством команд описанного выше языка программирования типа Си. Некоторые из команд могут состоять из нескольких операций чтения и записи в общую ячейку памяти (операции чтения/ записи являются атомарными для простых типов данных на архитектуре x86). Для того чтобы провести анализ на возникновение ситуации неупорядоченного доступа параллельных потоков к общим данным, необходимо тщательно определить переходы.

Действие a := p ~> q определяет переход

системы из одного состояния (l,s ) в другое (l,s ),

p q

где высказывания p и q характеризуют, соответственно, начальное и конечное состояния. Семантика переходов определяется следующим образом:

si*^s2*soN p~>q si|= pЛsi|= q;

sus2|= [p] si = s2Л si |= p;

s, s' |= a * a' :o s = si X s2 л s' = sj X s'2 л

л si' |= ai)л Сьs21= a);

si,s2 |= a ^ a :o если из si,s21= a, следует si, s21= a'.

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

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

Утверждение р устойчиво под действием а Stab(p,a) тогда и только тогда, когда Vs, 5 ' таких, что 5 |= р а (5,5 ') |= а следует 5 ' |= р.

Сначала нами была доказана лемма 1 о том, что наличие множественного числа регионов не влияет на истинность следующих свойств RGSep логики:

Stab(p,г-> д) о |= (г р)* д ^ р; Stab(p,(Я1 иЯ2)*) о Stab(p,Я1) аStab(p,Я2);

Stab (р1, a) а Stab (р2, a) о Stab (р1 а р2, a); atab(p1la1) V atab(p2,a2) оStab(p1 V р2,a, а /2) ;

Stab(p,a1) а Stab(p,a2) о Stab(p,a1 а a2).

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

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

Пример. Пусть 1, a1 = [Ь2 \ 2, Ь2 \ 3] и Ь2 \ 4, a2 = [Ц \ 5,Ц \ 6] причем Ц Ф Ь2, т. е. имеем, что S?aat^>11a1), Stab(p2,a2) - истина, а Stab( р1 * р2, a1 * a2) - ложь.

Этот факт связан с тем, что мы задаем высказывание на подмножестве общих состояний (аналогичная картина наблюдается и в LRG). Поэтому типичного определения инварианта как утверждения истинного «до» и «после» выполнения, нам недостаточно: необходимо еще требова-ниеточного инварианта I.

Будем говорить, что действие а защище-

но точным инвариантом I > a тогда и только тогда, когда инвариант имеет место в начальном и конечном переходах, удовлетворяющих а, и является точным инвариантом precise (I): а ^ (I ~> I) n precise (I).

Доказана лемма 2 (в оригинальном методе RGSep этой леммы нет, в LRG соответствующая лемма присутствует):

(Stab (pj, aj) n Stab (p2, a2) n pj ^ ^ I n (I > a) о Stab(pj * p2,aj * a2).

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

Напомним определения из логики RGSep: Lp_L = I q ^ p n Stab(q,R)} - слабейшее предусловие, устойчивое под действием R; fp"R = n{q | p ^ q n Stab(q,R)} - сильнейшее постусловие, устойчивое под действием R.

В логике RGSep показаны следующие свойства, которые остаются истинными и при нашем

разделении общей памяти на регионы (часть из которых скрыта от некоторых потоков):

p«• Гр!« «• Lp_L; (p^q)^(Гр1 ^ Гр 1); ( р ^ q) ^ (LpJR ^LpJR ).

Доказана лемма 3 о новых свойствах для логики RGSep (свойства истинны и на предложенной нами многорегиональной модели памяти):

I_pJr v LqJ* Lp vq_R; Lp л qJR ^LpJR ALqJR; Гр л q\ ^ Гр"к л rql; Гр v q\ ^ Гр1 v rq~R.

Правила вывода

Выводимость модифицированной тройки Хоара обозначена как R; G; l\ -{ pre}C{ post} означает, что если предусловия удовлетворяют pre, изменения общих состояний выполняются в соответствии с R, выполнение кода потока удовлетворяет G при защите точным инвариантом I, и если подпрограмма завершает работу, то постусловия удовлетворяют post.

По сравнению с логикой RGSep введено два новых правила для скрытия части общих данных и разбивки памяти на изменяемую и неизменную часть:

R;G;I\-{P * Y }C{Q * Г } Stab(M,R v G) I > {R',G'} R, G, I\-{P * M * Y}C{Q * M * Г }

R * R'; G * G';I * I'|-{p }C{q } I > {R, G}

(Frame);

(Hide).

Я, О,1\-{р]С{д }

Запись при слабейших предусловиях и сильнейших постусловиях будет иметь вид: Д;С;/|-{Р*[У_|}С{0*|У'|} vG) 1>{Я',С}

(Frame').

Здесь приведены примеры еще нескольких правил при слабейших предусловиях и сильнейших постусловиях:

R',G;l\-{\_pre1 V pre2]R }C{post} R;G;l\-{pre}C{\ post^} R-,G;l\-{pre}C{\ post2\]

(Disj);

(Conj).

R;G;l\-{pre]C{\ро$Ц a post2~]R}

Правила для пустых операторов, последовательных и зацикливания имеют стандартный вид:

Stab

R; G; I\ -{pre }skip{ post}

(Skip);

R, G, I |-{pre }C{post}

R, G, I |-{pre }C *{post}

(Loop);

R;G;l\-{p }Q{r} R;G;I\-{r }C2{q}

(Seq).

R; G;I| -{ p}Ci;C2{q}

К тем командам, которые не имеют доступа к общим данным, нужно использовать адаптированные правила из сепарационной логики:

I- {P }c{Q } 1 SpK * Ш1 (Prim).

R, G, I\-{Q}c{Q }

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

R v G2; Gi;I-{Pi * Т}Ci{Qi * T} I > {R, G}

R v Gi;G2;I|-{P2 * T}C2{Q2 * T>} T v T v T2 ^ I

-i-=-=- (Par).

R; Gi v G2; l| -{P * P2* T } Ci | C2 {P * P2*(T^ л T2)}

Запись при слабейших предусловиях и сильнейших постусловиях будет иметь вид:

} />{ВД

R* Г 1 L=-s

7?VGI;G2;/|-{P2

RvG^Il-iP^lT^C^Q,'

}C2{Q2*

RvG2

} TvTtvT2=>I

jgvGl

R-,G, vG^/HP *P2 *\т |vG2vG1} Q IIC2 {Р^Р.Ч

Г, Л ъ. )}

RvG2 RvGl

(Par').

В качестве примера здесь приведено правило для исполнения команд во взаимоисключающем режиме, которые имеют доступ к нескольким регионам:

\-{(р"*р[ *-*Рп)№отк{С}{(д"*д[*...*дп )}

Vie {1.....и}:

Stab^MrJ) Stab(qi,R(ri)) Pi -> q'i => Pi -> 4i (Pi -> q) с Gi rt) /,. > {Ri,Gi}

R,G,l\-{(p' * P[X * ••• * pr^)}atomic{C}{iq' * 9lrl *... *qr/)}

Для интерпретации выводимости как доказательства в смысле частичной корректности необходимо, чтобы система вывода обладала свойством непротиворечивости, что отражает доказанная теорема. Каждая выводимая формула - корректна: если R;G;l|-{p}C{p}, то R;G; I|= {p}C{ p}.

Практическое применение

С помощью предложенного метода верифицированы на отсутствие гонок несколько типичных программ добавления/удаления элемента из очереди, стека. Причем, в части из этих программ механизмы синхронизации реализованы с помощью структур, свободных от блокировок (lock-free).

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

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

Дальнейшая работа планируется в направлении исследования автоматизации процесса анализа на базе инструментов типа SmaПfootRG, ЬаЬеЫе/НО^

СПИСОК ЛИТЕРАТУРЫ

1. Vafeiadis, V. A marriage of rely/guarantee and separation logic [TeKCT]/V. Vafeiadis, M. Parkinson//Proc. 18th Int'l Conf. on Concurrency Theory (CONCUR'07): Lecture Notes in Computer Science.-2007.-Vol. 4703. -P. 256-271.

2. Jones, C. Specification and design of (parallel) programs [TeKCT]/C. Jones//Proc. of IFIP'83.-North-Holland, 1983.-P. 321-332.

3. Feng, X. Local rely-guarantee reasoning [TeKCT]/X. Feng//ACM Symp. on Principles of Prog. Lang.-2009.-P. 315-327.

4. Feng, X. On the relationship between concurrent separation logic and assume-guarantee reasoning [TeKCT]/X. Feng, F. Rodrigo, S. Zhong//Proc. 16th European Symp. on Prog. (ESOP'07): Lecture Notes in Computer Science.- 2007.-Vol. 4421.-P. 173-188.

5. Reynolds, C. Separation logic: A logic for shared mutable data structures [TeKCT]/C. Reynolds//Proc. 17th Annual IEEE Symp. on Logic in Computer Science (LICS'02).-IEEE Computer Society, 2002.-P. 55-74.

6. Gotsman, A. Proving that non-blocking algorithms don't block [TeKCT]/A. Gotsman, B. Cook, M. Parkinson,

V. Vafeiadis//Proc. 36th ACM. Symp. on Principles of Prog. Lang. (POPL'09).-ACM Press, 2009.

7. Кларк, Э.М. Верификация моделей программ: Model Checking [Текст]/Э.М. Кларк, О. Грамберг, Д. Пелед; Под ред. Р. Смелянского.-М.: МЦНМО, 2002. -416 с.

8. Алешина, Н.А. Логика и компьютер. Моделирование рассуждений и проверка правильности программ [Текст]/Н.А. Алешина, А.М. Анисов, П.И. Быстров.-М.: Наука, 1990.-240 с.

9. Feng, X. Local rely-guarantee reasoning [Текст]/Х. Feng//ACM Symp. on Principles of Prog. Lang.-ACM, 2009.-P. 315-327.

10. Dodds, M. Deny-guarantee reasoning [Текс^/M. Dodds, X. Feng, M. Parkinson, V. Vafeiadis// Proc. ES0P.-2009.-P. 363-377.

11. Cliff, B.Jones. Wanted: a compositional approach to concurrency [Текс^/B.Jones, Cliff//In Prog. Methodology. -Springer-Verlag, 2003.-P 5-15.

12. Vafeiadis, V. Modular fine-grained concurrency verification: PhD thesis [Текст]/У. Vafeiadis.-Univ. of Cambridge. Computer Lab., 2008.

УДК 658.512:004.42,658.512:519.87

К.Г. Жуков, Д.Н. Бутусов

КОРРЕКЦИЯ ПОГРЕШНОСТИ РЕШЕНИЯ УРАВНЕНИЯ ГАРМОНИЧЕСКОГО ОСЦИЛЛЯТОРА МЕТОДОМ ПОСЛЕДОВАТЕЛЬНОГО ИНТЕГРИРОВАНИЯ

Широкий класс динамических систем описывается дифференциальными уравнениями второго порядка. Поэтому представляется целесообразным обеспечить на основе методики коррекции погрешности разомкнутых интеграторов [1] уменьшение величины погрешности интеграторов, охваченных отрицательной обратной связью.

Уравнение второго порядка в общем виде может быть записано следующим образом:

y" + 2çray'+ra2y = га2x(t).

С нулевыми начальными условиями выражение (1) соответствует следующей передаточной функции:

Y (S ) га2

W (S ) =

X (S ) S2 + 2çraS +

В случае, когда х(?) = 0, уравнение (1) описывает свободные невынужденные колебания, а в случае, когда х(?) = 0 и с; = 0 - свободные незатухающие колебания.

Приведем уравнение (1) к виду:

y " =-2çray'-ra2 y + га2 x(t ), У "

— = -2qy -ay + ax(t). ю

Как правило, численные методы интегрирования требуют задания уравнений в нормальной форме Коши. Перейдем от уравнения (4) к системе уравнений:

[ у, = -2(ùçy, - соу2 + шх(0; [у2 =У1-