Run và tiến trình init()

Một phần của tài liệu Kiểm chứng tính đúng đắn hệ thống tính toán của chương trình bằng kiểm duyệt mô hình (Trang 29)

4. Cấu trúc luận văn

2.1.6.1.Run và tiến trình init()

Cách khởi tạo tiến trình trong tiến trình init là dùng toán tử run, khi tiến trình được khai báo mà không có từ khóa active.

Tiến trình init() luôn được khởi tạo đầu tiên nên luôn có pid = 0. Ví dụ 2.18: proctype A() { } proctype B() { } init { run A(); run B(); } 2.1.6.2. Atomic

Các lệnh được đặt trong atomic { } sẽ được thực hiện như một lệnh độc lập và không bị các lệnh khác ngoài nó chen vào. Việc sử dụng atomic nhằm giảm sự phức tạp của mô hình cần kiểm duyệt.

Ví dụ 2.19:

atomic {

temp = n; n = temp +1; }

Đoạn mã trong ví dụ 2.19 tương đương với n = n+1;

Có thể sử dụng atomic để kết hợp các câu lệnh giữa các tiến trình. Ví dụ 2.20:

chan ch = [0] of {init}

active proctype A() {atomic {

C; ch!1; D }

}

active proctype B() {atomic {

ch?1 E }

Trong ví dụ 2.20 sau khi khối lệnh C trong tiến trình A được thực thi, giá trị 1 (kiểu int) được gửi cho kênh ch có kiểu gặp (lệnh ch!1; được thực hiện), tiến trình B nhận dữ liệu trên kênh (ch?1) và khối lệnh E được thực thi, khi khối lệnh

E kết thúc, việc thực thi sẽ tự động chuyển về tiến trình A và thực thi khối lệnh

D.

Atomic được sử dụng để khởi tạo một số các tiến trình và đảm bảo không một tiến trình nào được thực hiện cho tới khi tất cả các tiến trình trong nó đều được thực hiện.

Ví dụ 2.21: khởi tạo hai tiến trình P, Q:

proctype P() { } proctype Q() { } init { run P(); run Q(); }

Trong ví dụ 2.21 do tiến trình init đã được khởi tạo và có thể chạy, khi đó một trong hai tiến trình P, Q có thể được chạy trước khi tiến trình còn lại được khởi tạo, điều đó là bất lợi, do vậy việc bổ sung atomic sẽ loại bỏ được điều này.

Ví dụ 2.22: proctype P() { } proctype Q() { } init { atomic { run P(); run Q(); } }

2.1.7. Cấu trúc điều khiển 2.1.7.1. Lệnh lựa chọn if 2.1.7.1. Lệnh lựa chọn if if :: biểu_thức_logic1 Lệnh_11; …; Lệnh_1n :: biểu_thức_logic2 Lệnh_21; …; Lệnh_2n :: biểu_thức_logicn Lệnh_n1; …; Lệnh_nn fi

Biểu thức logic có thể là true hay false. Ví dụ 2.23: active proctype P() { int a = 1, b = -4, c = 4; int d; d = b * b - 4 * a * c; if :: d < 0 ->

printf ("d = %d: no real roots\n", d) :: d == 0 ->

printf ("d = %d: dup licate real roots\n", d) :: d > 0 ->

printf ("d = %d: two real roots\n", d) fi

}

Trong ví dụ 2.23 sau khi tính được giá trị của d, cấu trúc if sẽ kiểm tra giá trị của d theo từng trường hợp, và trong ví dụ này sẽ in ra kết quả là 0.

2.1.7.2. Lệnh lặp do do do ::Biểu_thức_logic_1 Lệnh_11;…; Lệnh_1n; ::Biểu_thức_logic_2 Lệnh_21;…; Lệnh_2n; ::Biểu_thức_logic_n Lệnh_n1;…; Lệnh_nn; ::Biểu_thức_logic break; od; Ví dụ 2.24: active proctype P() { int x = 15, y = 20; int a = x, b = y;

do (adsbygoogle = window.adsbygoogle || []).push({});

:: a > b -> a = a - b :: b > a -> b = b - a :: a == b -> break od ;

printf ("The GCD of %d and %d = %d\n", x, y, a) }

Lệnh ifdo thể hiện tính không tất định của Promela: Nếu hai hay nhiều biểu thức logic có giá trị true, chuỗi lệnh theo sau một biểu thức bất kỳ trong số đó sẽ được thực thi.

2.1.7.3. Lệnh nhảy goto

Lệnh goto nhảy đến một đoạn chương trình sau một nhãn, tên nhãn được đặt trước dấu hai chấm.

Ví dụ 2.25:

do

::(x>=y) x = x - y; q = q + 1; ::(y>x) goto done;

od

done: skip;

2.2. Công cụ Spin

2.2.1. Kiểm chứng chương trình trong Spin 2.2.1.1. Đặc trưng của SPIN 2.2.1.1. Đặc trưng của SPIN

Spin (Simple Promela Interpreter) là một công cụ kiểm chứng, nó hỗ trỡ ngôn ngữ đặc tả hệ thống Promela. Spin được dùng để theo dõi những lỗi logic ở trong những bản thiết kế của hệ thống phân tán như hệ điều hành, giao thức truyền thông dữ liệu, thuật toán song song, giao thức báo hiệu tàu điện,...Ta có thể sử dụng Spin mà không cần phải dựng lên mô hình dưới dạng đồ thị trạng thái [5].

Spin hỗ trợ kiểm chứng mọi thuộc tính yêu cầu có thể biểu diễn dưới dạng LTL (Linear Temporal Logic – Logic thời gian tuyến tính), hoặc cũng có thể sử dụng các khẳng định – assertion để đặc tả một số thuộc tính cần kiểm chứng.

Ngôn ngữ đặc tả Promela được sử dụng để diễn tả mô hình hệ thống và thuộc tính của nó để kiểm chứng mô hình.

Spin có thể mô phỏng sự thực thi của hệ thống.

Việc sử dụng Spin rất đơn giản, hiệu quả cao, và nó phù hợp để kiểm chứng hệ thống phân tán.

2.2.1.2. Mô hình hệ thống trong SPIN

Các hệ thống được mô hình hóa trong Spin như là một tập các tiến trình (mạng các Automata), được chạy song song theo chế độ đan xen và giao tiếp với nhau qua các thông điệp hay qua chia sẻ các biến.

Hình 2.1: mô hình của hệ thống trong Spin [5]

2.2.1.3. Cấu trúc của Spin

Cấu trúc cơ bản của Spin được thể hiện trong hình 2.2. Luồng công việc bắt đầu từ việc đặc tả mô hình ở mức cao của hệ thống hiện thời, qua giao diện Front-End của Xspin (giao diện đồ họa người dùng của Spin), sau đó kiểm tra lỗi cú pháp, thực hiện mô phỏng tương tác cho đến khi người dùng nhận được sự tin cậy cơ bản mô hình thuộc tính mong đợi. Một chương trình Promel đúng đắn có thể yêu cầu được tạo từ một công thức được đặc tả trong logic thời gian tuyến tính (LTL). Sau đó Spin được sử dụng để tạo một chương trình xác minh tối ưu. Chương trình xác minh này được biên dịch với thời gian biên dịch có thể được chọn trước, và sau đó thực hiện xác minh chính nó. Nếu bất kỳ phản ví dụ nào thỏa mãn yêu cầu tính đúng đắn được phát hiện thì chúng có thể được đưa trở lại để mô phỏng trong Spin. Việc mô phỏng có thể được kiểm tra chi tiết để xác định nguyên nhân [3].

Shared Variables (shared memory)

Channels

System Global Scope

access access

send & receive send & receive

Pro ce ss A lo cal sc op e Pro ce ss B lo cal sc op e

Hình 2.2: Cấu trúc của Spin [3]

2.2.1.4. Giả lập ngẫu nhiên (adsbygoogle = window.adsbygoogle || []).push({});

Spin biên dịch và chạy một chương trình Promela trong chế độ giả lập ngẫu nhiên rồi in ra các trạng thái của chương trình, sau đó in ra các trạng thái của thuộc tính.

Một trạng thái của chương trình là bộ các giá trị của các biến, biến đếm vị trí các tiến trình. Một tính toán của chương trình là chuỗi các trạng thái bắt đầu bởi trạng thái khởi tạo và tiếp tục với những trạng thái xuất hiện sau khi mỗi câu lệnh được thực hiện [3].

Ví dụ 2.26.Chương trình với 2 tiến trình

1 byte n=0; 2 active proctype P(){ 3 n=1; 4 printf("Process P, n=%d\n",n); 5 } 6 active proctype Q(){ 7 n=2; Model-Specific ANSI C code Executable Verifier Counter - Examples XSPIN Front – End (Tcl/Tk code) PROMELA Parser Random/Guided Simulation LTL Parser and Translator Verifier Generator Syntax Error Reports

8 printf("Process Q, n=%d\n",n); 9 }

Trong ví dụ 2.26 biến n được khởi tạo với giá trị 0, chương trình bao gồm 2 tiến trình: PQ tương ứng gán biến n giá trị 1 hoặc 2 và in ra tên tiến trình và giá trị của n.

Chạy chương trình trong ví dụ 2.26 trên ở chế độ Random, chương trình không có lỗi và nhận được kết quả:

Starting P with pid 0

0: proc - (:root:) creates proc 0 (P) Starting Q with pid 1

0: proc - (:root:) creates proc 1 (Q) 1 Q 7 n = 2 Process Statement n 0 P 3 n = 1 2 Process P, n=1 0 P 4 printf('Proces 1 Process Q, n=1 1 Q 8 printf('Proces 1 4: proc 1 (Q) terminates 4: proc 0 (P) terminates 2 processes created

Trong ví dụ 2.26, đầu tiên PQ lần lượt được tạo với pid (process id) là 0 và 1. Các lệnh trong cả hai tiến trình được thực thi xen kẽ một cách tùy ý. Xspin hiển thị trạng thái của chương trình sau mỗi câu lệnh được thực thi (theo thứ tự: pid, tên tiến trình chứa câu lệnh, vị trí câu lệnh, nội dung câu lệnh đã được cắt ngắn, giá trị của biến).

Trong lần chạy ở trên các câu lệnh được thực hiện theo thứ tự:

n=2 n=1 prinf(Q) prinf(P)

Do vậy hai hàm printf đều in ra n=1

2.2.1.5. Kiểm chứng (Verify)

Assertion là cách đơn giản để kiểm tra chương trình. Một assertion là một mệnh đề được đặt trong 1 chương trình mà ta cho rằng mệnh đề sẽ luôn đúng tại vị trí đó. Spin sẽ tính toán các assertion trong quá trình tìm kiếm phản ví dụ trong không gian trạng thái của chương trình.

Ví dụ 2.27. Tìm số lớn nhất trong 2 số active proctype P() { int a = 5, b = 5; int max; if :: a >= b -> max = a :: b >= a -> max = b fi;

assert (a >= b -> max == a : max == b) }

Đoạn mã trong ví dụ 2.27 tìm số lớn nhất trong 2 số ab, trong câu lệnh

if, nếu a >=b biến max sẽ được gán giá trị a, nếu b>=a biến max sẽ được gán giá trị b, ở cuối chương trình ta kiểm tra lại bởi biểu thức logic (a >= b -> max = = a : max = = b).

Chạy đoạn mã trong ví dụ 2.27 ở chế độ Verify, kết quả là không có lỗi vi phạm nào được thông báo từ chương trình.

(Spin Version 4.3.0 -- 22 June 2007) + Partial Order Reduction

Full statespace search for:

never claim - (none specified) assertion violations +

cycle checks - (disabled by -DSAFETY) invalid end states +

State-vector 24 byte, depth reached 2, ••• errors: 0 ••• 3 states, stored

1 states, matched

4 transitions (= stored+matched) 0 atomic steps

hash conflicts: 0 (resolved) 2.302 memory usage (Mbyte) unreached in proctype P (0 of 8 states)

Ví dụ 2.28: Chương trình có chứa lỗi (adsbygoogle = window.adsbygoogle || []).push({});

active proctype P() { int a = 5, b = 6; int max;

:: a >= b -> max = a :: b >= a -> max = b+1 fi;

assert (a >= b -> max == a : max == b) }

Trong ví dụ 2.28, ta cũng tìm số lớn nhất trong 2 số a, b nhưng khi b>=a, biến max lại được gán giá trị b+1, do vậy biểu thức (a >= b -> max = = a : max = = b) không được thỏa mãn.

Khi chạy Verify đoạn mã trong ví dụ 2.28 sẽ đưa ra thông báo assertion bị vi phạm.

pan: assertion violated ( ((a>=b)) ? ((max==a)) : ((max==b)) ) (at depth 0)

pan: wrote max.pml.trail

(Spin Version 4.3.0 -- 22 June 2007) Warning: Search not completed + Partial Order Reduction Full statespace search for:

never claim - (none specified) assertion violations +

cycle checks - (disabled by -DSAFETY) invalid end states +

State-vector 24 byte, depth reached 2, ••• errors: 1 ••• 3 states, stored

0 states, matched

3 transitions (= stored+matched) 0 atomic steps

hash conflicts: 0 (resolved) 2.302 memory usage (Mbyte)

2.2.2. Giao diện người dùng Xspin

Màn hình chính của Xspin là một cửa sổ văn bản hiển thị các tập tin được sử dụng, nó giống như một trình soạn thảo văn bản. Xspin có giao diện thân thiện người dùng cung cấp khả năng chỉnh sửa và tìm kiếm.

Hình 2.3: Màn hình cửa sổ chính của XSpin

Các chức năng trong menu File, Edit, View, Help trợ giúp việc mở file, lưu file, các thao tác sao chép, chỉnh sửa, hiển thị, và thông tin trợ giúp. Menu Run chứa các chức năng chính để kiểm tra, mô phỏng, và xác minh mô hình qua chương trình.

Mỗi chức năng trong menu Run thực hiện nhiệm vụ riêng:

 Run Syntax Check: Luôn là bước được thực hiện đầu tiên sau mỗi sự thay đổi của chương trình. Chức năng này sẽ kiểm tra cú pháp của chương trình viết bằng ngôn ngữ Promela.

 Run Slicing Algorithm: Xác định những thành phần không ảnh hưởng đến các thuộc tình trong mô hình. Nó thể hiện sự phân tích lưu lượng dữ liệu.

 Set Simulation Parameters: Là chức năng hỗ trợ gỡ lỗi quan trọng. Chức năng này sẽ thiết lập các thông số hiển thị:

 MSC Panel (Message Sequence Chart): Bảng điều khiển các thông số hiển thị của biểu đồ tuần tự thông điệp.

 Time Sequence Panel - with: Bảng điều khiển các thông số giao tiếp tuần tự theo thời gian.

 Data Values Panel: Điều khiển trình bày giá trị dữ liệu. Tùy chọn gồm các kênh đệm các biến địa phương và biến toàn cục.

 Random : Yêu cầu người sử dụng cung cấp giá trị trong Seed Value.

 Run Simulation

 Việc thiết lập các thông số hiển thị phải được thực hiện ít nhất một lần trước khi thực hiện Run Simulation.

 Việc thiết lập mặc định thông số hiển thị sẽ sinh ra 3 cửa sổ sau:

o Simulation Output: Cung cấp 2 phương thức là chạy từng bước (Single Step) hoặc chạy liên tục (Run). (adsbygoogle = window.adsbygoogle || []).push({});

o Data Values: Hiển thị kết quả các giá trị dữ liệu.

o Sequence Chart: Đưa ra biểu đồ tuần tự.

Hình 2.6: Cửa sổ khi chạy chức năng Run Simulation

 Set Verification Parameters: Thiết lập các tham số để xác minh hệ thống:

 Correctness Properties: Safety, Liveness.

 Search mode.

 A full queue.

 Verify an LTL property.

Hình 2.7: Cửa sổ chính chức năng Set Verification Parameters

 Run Verification: Thực hiện xác minh hệ thống qua chương trình.

 Linear Time Temporal Logic Formulae: Công thức logic thời gian tuyến tính, chức năng này cho phép: Nhập vào công thức logic thời gian tuyến tính (thuộc tính cần kiểm duyệt). Chỉ ra có hay không thuộc tính cần giữ, bằng cách lựa chọn all executions (desired behaviour) hay no executions (error behaviour). Nhập vào một định nghĩa đối với mỗi hằng số mệnh đề trong cửa sổ phụ “Symbol Definitions” (nếu cần). Nhấn “Generate” để tạo cấu trúc Never Claim và nhấn “Run Verification” để xác minh.

Hình 2.9: Cửa sổ khi chạy chức năng LTL Property Manager

 View Spin Automaton for each proctype (FSM View): Đưa ra sự chuyển đổi giữa các trạng thái trong từng tiến trình.

2.2.3. Logic thời gian tuyến tính (LTL - Linear Temporal Logic) trong Spin

Khi sử dụng assertion, Spin sẽ tính toán assertion tại một vị trí nhất định trong chương trình mà ở đó assertion được thêm vào, do đó assertion bị hạn chế trong việc biểu diễn tính chất của mô hình.

Từ đó cần dùng đến logic thời gian tuyến tính LTL, LTL mạnh mẽ hơn trong việc biểu diễn tính chất của mô hình hệ thống. Với LTL ta có thể diễn tả những tính chất chung cần được thỏa mãn mà không liên quan đến một vị trí nào trong chương trình.

LTL phù hợp với các hệ thống tương tác khi tính đúng đắn của hệ thống không chỉ thể hiện ở kết quả tính toán mà ta phải kiểm tra sự giao tiếp và thực thi các tiến trình trong hệ thống [2].

2.2.3.1. Cú pháp Logic thời gian tuyến tính

Các công thức LTL được tạo ra từ các phép toán mệnh đề, công thức các phép toán mệnh đề được tạo ra từ mệnh đề nguyên thủy (p, q,…) và các phép toán trong bảng 2.3:

Bảng 2.3: Các phép toán mệnh đề trong LTL [6]

Operator Math Spin

not ¬ !

and  &&

or  ||

implies → ->

equivalent ↔ <->

LTL hình thức hóa các tính chất về thời gian bởi các toán tử thời gian. Bảng 2.4: Các phép toán thời gian của LTL [6]

Operator Math Spin

always □ [ ]

eventully ◊ < > (adsbygoogle = window.adsbygoogle || []).push({});

until U U

Các phép toán □ và ◊ là phép toán một ngôi, phép toán U là phép toán hai ngôi. Các phép toán thời gian và phép toán mệnh đề được kết hợp tự do với nhau. Chẳng hạn công thức:

□ ( (p ∧ q) → r U (p ∨ r) ) , [] ( (p && q) -> r U (p || r) ) [ ] A: hệ thống luôn luôn mang tính chất A.

<> A: nếu hệ thống có tính chất A tại một thời điểm nào đó trong tương lai thì ta nói hiện tại hệ thống có tính chất <> A.

A U B: tại thời điểm hiện tại hệ thống có tính chất A U B có nghĩa là: nếu trong một thời điểm nào đó trong tương lai hệ thống có tính chất B thì hệ thống có tính chất A tại tất cả các thời điểm từ hiện tại cho tới khi nó mang tính chất B.

Thời gian trong LTL là thời gian “trừu tượng” do LTL quan niệm thời gian một cách rời rạc, chỉ bao bao gồm những thời điểm đơn lẻ [2].

2.2.3.2. Biểu diễn tính chất bất biến của hệ thống bằng LTL

Trong nhiều trường hợp, hệ thống xây dựng phải thỏa mãn một tính chất bất biến nào đó. Với LTL ta biểu diễn tính chất đó bởi toán tử [].

Ví dụ 2.29: Tính chất “mỗi yêu cầu (request) cuối cùng đều dẫn tới một phản hồi (response)” ta biểu diễn như sau:

2.2.4. Cấu trúc Never claim

Có những tính chất mà ta mong muốn nó không bao giờ được xuất hiện trong hệ thống. Trong Promela nó được biểu diễn bởi never claim.

Một phần của tài liệu Kiểm chứng tính đúng đắn hệ thống tính toán của chương trình bằng kiểm duyệt mô hình (Trang 29)