Kỹ thuật phát hiện lỗi sử dụng LTSA

Một phần của tài liệu Đặc tả và kiểm chứng thiết kế của hệ thống tương tranh (Trang 34)

Từ kết quả thử nghiệm như hình 3.16 của bài toán Supermarket, chúng ta nhận thấy rằng, thời điểm chọn nút stop giá trị biến đếm đối tượng chia sẽ của mỗi luồng là 20 thì giá trị biến đếm counter mong muốn phải là 60. Tuy nhiên thực tế như chỉ ra trong hình 3.16 kết quả chỉ là 55. Một câu hỏi được đặt ra là tại sao kết quả bị sai? Để khám

phá ra điều này, chúng ta mô hình bài toán ở cấp độ đọc và viết lên biến đối tượng chia sẽ. Mô hình xây dựng gồm một tiến trình VAR biểu diễn dưới dạng tiến trình FSP để mô tả việc truy cập để đọc và viết lên biến đối tượng chia sẽ. Trong mô hình này mỗi đối tượng được miêu tả như một máy hữu hạn trạng thái FSP, phạm vi tham số của tiến trình là T=[0..4]. Bảng chữ cái của tiến trình VAR là một tập các hành động mà nó có thể tham gia được chỉ ra là một tập VarAlpha như sau:

set VarAlpha = {value.{read[T],write[T]}}

Tiến trình VAR bao gồm hai hành động read và write được miêu tả một cách đệ quy bắt đầu từ VAR[0] như hình 3.17.

Hình 3.17. Tiến trình VAR.

Trong mô hình mới này hành động increment để tăng biến đếm đối tượng chia sẽ được mô hình bằng cách sử dụng các hành động read để đọc dữ liệu biến chia sẽ và hành động write để cập nhật giá trị biến chia sẽ được xác định bởi INCREMENT bên trong TURNSTILE như miêu tả ở hình 3.18.

Hình 3.18. Hành động INCREMENT.

Hình 3.19. Tiến trình TURNSTILE.

Bảng chữ cái của tiến trình TURNSTILE được mở rộng với bảng chữ cái VarAlpha sử dụng cấu trúc bảng chữ cái mở rộng +{..}. Một tiến trình TURNSTILE không bao giờ có hành động value.write[0] vì nó luôn tăng giá trị mà nó đọc được. khách đến nhất định nhưng có thể kết thúc tại bất kỳ thời điểm nào, tuy nhiên nó

VAR=VAR[0]

VAR[u:T]= (read[u] ->VAR[u] |write[v:T]->VAR[v]).

INCREMENT = (value.read[x:T] -> value.write[x+1] -> RUN)+VarAlpha.

const N = 4 range T = 0..N

set VarAlpha = { value.{read[T],write[T]} } VAR = VAR[0],

VAR[u:T] = (read[u] ->VAR[u] | write[v:T]->VAR[v]). TURNSTILE = (go -> RUN),

RUN = (arrive -> INCREMENT | end -> TURNSTILE),

const N = 4 range T = 0..N

set VarAlpha = { value.{read[T],write[T]} } VAR = VAR[0],

VAR[u:T] = (read[u] -> VAR[u] | write[v:T] ->VAR[v]). TURNSTILE = (go -> RUN),

RUN = (arrive-> INCREMENT | end -> TURNSTILE),

INCREMENT = (value.read[x:T] -> value.write[x+1] -> RUN ) +VarAlpha.

||SUPERMARKET = (east:TURNSTILE || east:TURNSTILE || south:TURNSTILE

|| {east,west,display,south}::value:VAR) /{go/{ east, west, south}.go,

end/{east, west, south}.end}.

không thể kết thúc lúc đang cập nhật giá trị biến chia sẽ. Tiến trình TURNSTILE được miêu tả như hình 3.19.

Tiến trình SUPERMARKET là sự kết hợp của các thành phần east, west, south và {east, west, south, display}::value:VAR, trong đó east, west, south là các đối tượng của tiến trình TURSNTILE.

Tiền tố {east, west, south display}::value:VAR dùng để thay thế mọi hành động value.read, value.write và south.write bằng tập hành động tương ứng là {east, west, south, display}.value.read và {east, west, south, display}.write.

Nhãn /{go/{east, west, south}.go, end /{east,wes, south}.end} chính là việc gán lại nhãn {east, west, south}.go bằng nhãn go và nhãn{east, west, south}.end được gán lại bằng nhãn end, việc gán lại nhãn này nhằm đảm bảo rằng tiến trình hỗn hợp SUPERMARKET đồng bộ trên biến chia sẽ VAR. Mô hình mới này được miêu tả đầy đủ như hình 3.20. LTS tương ứng với FSP của SUPERMARKET có đến 2000 trạng thái nên không thể minh họa ở đây được.

Hình 3.20. Tiến trình Supermarket.

Bây giờ chúng sử dụng công cụ LTSA để animate mô hình nhằm đưa ra vết hành động cho kịch bản đầu vào cụ thể để kiểm tra tiến trình hỗn hợp hoạt động đúng hay

sai, chẳng hạn vết trong hình 3.21 minh họa trường hợp trong đó có một east đến, một west đến và một south đến và sau đó hành động end xảy ra. (adsbygoogle = window.adsbygoogle || []).push({});

Hình 3.21. Kết quả test được đưa ra bởi Animator.

Hình 3.22. Tiến trình TEST và tiến trình CHECK.

Theo kết quả ở hình 3.21, vết được đưa ra là chính xác sau khi có ba luồng vào thì giá trị của biến đối tượng chia sẽ cũng có giá trị là 3. Tuy nhiên đây chỉ là một trường hợp, chúng ta cần kiểm thử với nhiều đầu vào cụ thể để xem thiết kế thiết kế đã đúng với mọi trường hợp chưa. Để tự động tìm kiếm lỗi chúng ta kết hợp với một tiến trình

TEST = TEST[0], TEST[v:T] =(

when(v<N){ east.arrive,west.arrive, south.arrive} ->TEST[v+1] | end->CHECK[v]

),

CHECK[v:T] = (

display.value.read[u:T] -> (when (u==v) right -> TEST[v] | when (u!=v) wrong -> ERROR )

TEST với tiến trình SUPERMARKET nhằm đưa ra tín hiệu khi có vết hành động sai xảy ra. Tiến trình TEST đếm tổng số sự kiện east.arrive, west.arrive và south.arrive. Khi hành động end xảy ra, nó sử dụng tiến trình CHECK để kiểm tra rằng giá trị lưu giữ có bằng tổng số sự kiện đến không? Nếu hai giá trị này không bằng nhau thì có một lỗi xảy ra và tiến trình TEST chuyển vào trạng thái ERROR. Tiến trình TEST và tiến trình CHECK được định nghĩa như hình 3.22.

Tiến trình TEST kết hợp SUPERMARKET cho ta tiến trình tổng hợp TESTSUPERMARKET như sau:

||TESTSUPERMARKET = (SUPERMARKET || TEST).

Bây giờ chúng ta sử dụng công cụ LTSA để phân tích mô hình FSP này để thấy rằng trạng thái ERROR có xảy ra trong tiến trình TESTSUPERMARKET không. Sau khi dùng LTSA để kiểm tra thì ta thu được một vết dẫn đến ERROR được đưa ra như hình 3.23.

Hình 3.23. Kết quả sai được đưa ra bởi Animator.

Kết quả ở hình 3.23 cho thấy rằng các increment bị mất là do các biến chia sẽ mà cụ thể ở đây là biến đếm đối tượng chia sẽ không được cập nhật tự động. Do đó cả luồng east và west đều đọc giá trị 0 và viết giá trị 1. Nên khi hành động end xảy ra thì giá trị biến lưu giữ là 1 còn tổng số sự kiện arrive là 2. Vậy hai giá trị này không bằng nhau nên có một lỗi ERROR xảy ra.

Từ phân tích và kết quả thử nghiệm trên ta thấy rằng mặc dù về mặt logic thì đúng nhưng chương trình hoạt động vẫn bị sai và các increment bị mất là do hành động read và write xen kẽ nhau một cách tùy tiện mà không có sự ràng buộc nào cả hay nói cách khác chương trình hoạt động sai chính là do lỗi ngữ nghĩa xảy ra ở khâu thiết kế.

Chƣơng 4. Đặc tả và kiểm chứng thiết kế của hệ thống tƣơng tranh sử dụng LTSA

Một bản thiết kế đặc biệt là thiết kế của hệ thống tương tranh, dù cẩn thận và chi tiết đến đâu cũng có thế tồn tại thiếu sót, chính vì vậy mô hình hóa thiết kế là một cách để kiểm chứng hiệu quả nhất. Phương pháp mô hình hóa được sử dụng rất rộng rãi trong kỹ thuật nhằm mô tả những đặc trưng của đối tượng đang quan tâm. Chúng ta gọi quá trình này là quá trình đặc tả đối tượng. Khi chúng ta kiểm tra trên mô hình sẽ cho kết quả tương đương với kết quả kiểm tra trên đối tượng thực. Trong thiết kế cũng vậy, mô hình hóa thiết kế sẽ cho phép chúng ta kiểm tra tính đúng đắn của nó trước khi đưa vào cài đặt. Đây là yêu cầu bắt buộc trong quy trình phát triển phần mềm đặc biệt là các phần mềm có yêu cầu chất lượng cao. Chương này trình bày một kỹ thuật đặc tả và kiểm chứng thiết kế của hệ thống tương tranh sử dụng công cụ LTSA.

4.1. Phƣơng pháp đặc tả

4.1.1. Đặc tả thiết kế của chƣơng trình tƣơng tranh

Chương trình tương tranh là chương trình có sự kết hợp của hai hay nhiều tiến trình có chia sẽ tài nguyên dùng chung với nhau và chúng có cùng một số thao tác lên phần dữ liệu dùng chung này tại cùng một thời điểm. Để thực hiện đặc tả chương trình tương tranh, chúng tôi đặc tả mỗi tiến trình của nó dưới dạng một máy hữu hạn trạng thái được gán nhãn (LTS) bằng ngôn ngữ FSP (Ngôn ngữ FSP và các thành phần của nó được miêu tả trong chương 2 – Các kiến thức cơ bản). Khi có được đặc tả của tất cả các tiến trình của chương trình dưới dạng các máy hữu hạn trạng thái được gán nhãn, chúng tôi xây dựng đặc tả của cả chương trình bằng cách ghép nối các đặc tả của các tiến trình bằng phép toán ghép nối song song như định nghĩa ở Chương 2.

4.1.2. Đặc tả thuộc tính cần kiểm chứng

Thực hiện kiểm chứng tức là xem xét chương trình có thỏa mãn thuộc tính cần kiểm chứng hay không. Trong luận văn này, chúng tôi chỉ quan tâm đến các thuộc tính an toàn – một lỗi nào đó không được xảy ra trong quá trình thực hiện của chương trình. Để thực hiện điều này, trước hết chúng ta sẽ mô hình hóa thuộc tính này dưới dạng một máy hữu hạn trạng thái được gán nhãn (tương tự như đặc tả của các tiến trình) bằng ngôn ngữ FSP. Đặc tả này sau đó sẽ được bổ sung thêm một trạng thái lỗi và các hàm chuyển từ tất cả các trạng thái của thuộc tính đến trạng thái này. Các hàm chuyển này mô tả các hành động dẫn đến trạng thái lỗi của hệ thống.

4.2. Kiểm chứng

Kiểm chứng hệ thống tương tranh nói riêng hay đối với việc kiểm chứng của một hệ thống bất kỳ là việc xem xét hệ thống này có thỏa mãn các thuộc tính cần kiểm chứng hay không? Đối với kiểm chứng thiết kế cũng vậy, sau khi chúng ta đã có đặc tả của thiết kế và thuộc tính cần kiểm chứng, bằng phép ghép nối song song chúng ta tích hợp các thành phần này để được thành phần tổng hợp của hệ thống.

Tư tưởng của việc kiểm chứng là duyệt xem có tồn tại ít nhất một dẫn xuất từ trạng thái khởi tạo trong tiến trình tổng hợp này có thể dẫn đến trạng thái lỗi π hay không (về trạng thái lỗi π được định nghĩa ở phần 2.1). Nếu có một dẫn xuất như thế thì chúng ta nói rằng thiết kế của chúng ta vi phạm thuộc tính mà chúng ta cần kiểm chứng. Ngược lại, nếu không có dẫn xuất đến trạng thái lỗi π thì thiết kế của chúng ta thỏa mãn thuộc tính cần kiểm chứng.

Để thực hiện điều này một cách tự động, chúng ta sử dụng công cụ LTSA (Về công cụ LTSA được miêu tả ở chương 2) với đầu vào là LTS của tiến trình cần kiểm chứng để kiểm tra xem thiết kế của chúng ta có vi phạm thuộc tính cần kiểm chứng không. Trong trường hợp thiết kế bị sai chúng ta sẽ tiến hành phân tích kết quả được trả lại bởi LTSA để tìm ra nguyên nhân bị sai để từ đó tiến hành hiệu chỉnh thiết kế và thực hiện kiểm chứng lại.

4.3. Áp dụng phƣơng pháp đặc tả vào bài toán tƣơng

Để minh họa cho phương pháp đặc tả và kiểm chứng, chúng tôi tiến hành đặc tả và kiểm chứng thiết kế của một hệ thống tương tranh Supermarket đã được miêu tả bằng ngôn ngữ FSP như trình bày ở chương 3 và được miêu tả trong hình 3.20.

4.3.1. Đặc tả thiết kế của bài toán chƣơng trình tƣơng tranh

Như chỉ ra trong hình 3.20, thiết kế hệ thống Supermarket có bốn thành phần. Do đó để đặc tả thiết kế này chúng ta sẽ tiến hành đặc tả từng thành phần bằng cách miêu tả từng thành phần này như một tiến trình và mỗi tiến trình được miêu tả dưới dạng một máy hữu hạn trạng thái bằng ngôn ngữ FSP. Quá trình đặc tả được miêu tả như sau: (adsbygoogle = window.adsbygoogle || []).push({});

Hằng số N=4 là phạm vi tham số của tiến trình, tập các hành động gồm có hai hành động value.read và value.write : set VarAlpha = {value.{read[T],write[T]}}

Tiến trình VAR xuất phát từ VAR[0], u là chỉ số của tiến trình và phạm vi của u=[0..4]. Tiến trình VAR được miêu tả dưới dạng ngôn ngữ FSP như hình 4.1.

Hình 4.1. FSP của tiến trình VAR.

LTS tương ứng với tiến trình VAR có các thành phần như sau:

- Tập các trạng thái : Q = {VAR[0] , VAR[1], VAR[2], VAR[3], VAR[4]} = {0, 1, 2, 3, 4}

- Trạng thái ban đầu : Q0 = {VAR[0]} = {0}

- Tập nhãn các hành động L = {read[u:T], write[u:T]}

VAR = VAR[0],

VAR[u:T] = (read[u] -> VAR[u] | write[v:T] -> VAR[v]).

- Tập quy tắc chuyển trạng thái δ như sau:

Với mỗi VAR[u] tương ứng với một trạng thái trong máy hữu hạn trạng thái sẽ có hai lựa chọn cho hành động tiếp theo hoặc là read[u] ->VAR[u] hoặc là

write[v:T]->VAR[v] với v = [0..4]. Do đó với mỗi trạng thái thứ u ta có số phép chuyển trạng thái ở bước tiếp theo là tích Đề các ((read[u] -> VAR[u]) x (write[v:T] -> VAR[v]).

Máy hữu hạn trạng thái LTS đầy đủ của tiến trình VAR được miêu tả như hình 4.2.

Hình 4.2. LTS của tiến trình VAR.

Tiến trình TURNSTILE có nhãn hành động đầu tiên là go, và được định nghĩa thông qua tiến trình cục bộ RUN như hình 4.3.

Hình 4.3. Miêu tả tiến trình TURNSTILE qua tiến trình RUN.

δ = {(0, read[0], 0), (0, write[0], 0), (0, write[1], 4), (0, write[2], 3), (0, write[3], 2), (0, write[4], 1), (1, read[4], 1), (1, write[0], 0), (1, write[1], 4), (1, write[2], 3), (1, write[3], 2), (1, write[4], 1), (2, read[3], 2), (2, write[0], 0), (2, write[1], 4), (2, write[2], 3), (2, write[3], 2), (2, write[4], 1), (3, read[2], 3), (3, write[0], 0), (3, write[1], 4), (3, write[2], 3), (3, write[4], 1), (3, write[4], 1), (4, read[1], 4), (4, write[0], 0), (4, write[1], 4), (4, write[2], 2), (4, write[3], 2), (4, write[4], 1)}

Tiến trình RUN có sự dịch chuyển trạng thái từ trạng thái ban đầu và có một trong hai lựa chọn, nếu sự dịch chuyển theo nhãn end thì chuyển về TURNSTILE, nếu sự

dịch chuyển theo nhãn arrive thì chuyển đến hành động INCREMENT. Tiến trình

RUN được miêu tả bằng ngôn ngữ FSP như hình 4.4.

Hình 4.4. Tiến trình RUN.

Hành động INCREMENT là một chuỗi bao gồm hai hành động read để đọc giá trị biến chia sẽ và write để cập nhật biến chia sẽ đối tượng được miêu tả như hình 4.5.

Hình 4.5. Tiến trình INCREMENT.

INCREMENT không có hành động value.write[0] vì nó luôn tăng giá trị mà nó đọc được. Vì thế tiến trình TURNSTILE thiếu mất hành động value.write[0] nên tập hành động mà tiến trình này tham gia ít hơn tập hành động được định nghĩa trong tập hành động VarAlpha = {value.{read[T],write[T]}}. Do đó bảng chữ cái của TURNSTILE được mở rộng với bảng chữ cái VarAlpha bằng cách sử dụng cấu trúc bảng chữ cái mở rộng +{..}.

Kết hợp các tiến trình RUN và INCREMENT ta có tiến trình TURNSTILE được miêu tả đầy đủ như hình 4.6.

Hình 4.6. Tiến trình TURNSTILE.

RUN = (arrive -> INCREMENT | end -> TURNSTILE )

INCREMENT = (value.read[x:T]

-> value.write[x+1]->RUN )

LTS của tiến trình TURNSTILE có các thành phần được xác định như sau: - Tập các trạng thái Q: (adsbygoogle = window.adsbygoogle || []).push({});

Qua hình 4.6 ta thấy rằng từ TURNSTILE để chuyển sang RUN cần một phép chuyển trạng thái, đối với tiến trình RUN có hai phép chuyển trạng thái và tiến trình INCREMENT có năm phép chuyển trạng thái tương ứng như sau:

 value.read[0] -> value.write[1]->RUN  value.read[1] -> value.write[2]->RUN  value.read[2] -> value.write[3]->RUN  value.read[3] -> value.write[4]->RUN  value.read[4] -> value.write[5]->RUN

Do đó tổng số trạng thái của TURNSTILE là 1+2+5 = 8.

Ký hiệu tập trạng thái này là: Q = {Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7}. - Trạng thái ban đầu là: Q0 = TURNSTILE

- Tậpnhãn các hành động:

L= {go, arrive, end, value.read[x:T], value.write[x+1] với T = [0..4]}. -Tập quy tắc chuyển trạng thái δ = {Q x L x Q} được miêu tả như sau:

Mô hình LTS của tiến trình thành phần TURNSTILE được miêu tả như hình 4.7.

δ= {(0, go, 1), (1, end, 0), (1, arrive, 2),

(2, value.read[0], 7), (7, value.write[1], 1), (2, value.read[1], 6), (6, value.write[2], 1), (2, value.read[2], 5), (5, value.write[3], 1), (2, value.read[3], 4), (4, value.write[4], 1), (2, value.read[4], 3), (3, value.write[5], 1)}

Hình 4.7. Mô hình LTS của tiến trình TURNSTILE.

Bằng phép toán song song, kết hợp bốn tiến trình east, west và south và {display,east,west,south}::value:VAR ta được tiến trình SUPERMARKET như miêu tả ở hình 4.12. Với east, west và south là ba đối tượng của tiến trình thành phần TURNSTILE. Do vậy LTS của tiến trình east, west và south có dạng LTS của TURNSTILE, chúng được miêu tả như hình 4.8 và hình 4.9 và hình 4.10.

Hình 4.9. LTS của tiến trình thành phần west.

Tiến trình thành phần {east,west,south,display}::value:VAR là một dạng của tiến trình VAR nhưng các hành động value.read và value.write được thay bằng các hành động {east,west,south,display}.value.read và {east,west,south,display}.value.write tương ứng. LTS của tiến trình này được miêu tả như hình 4.11.

Nhãn /{go/{east,west,south}.go, end/{east,west,south}.end} nhằm gán lại nhãn {east,west,south}.go bằng nhãn go và gán lại nhãn { east,west,south}.end bằng nhãn end. Việc gán lại nhãn này đảm bảo rằng tiến trình kết hợp SUPERMARKET đồng bộ trên biến chia sẽ VAR.

const N = 4 range T = 0..N

set VarAlpha = {value.{read[T],write[T]}} VAR = VAR[0],

VAR[u:T] = (read[u] -> VAR[u] | write[v:T] -> VAR[v]). TURNSTILE = (go -> RUN),

RUN = (arrive-> INCREMENT | end -> TURNSTILE),

INCREMENT = (value.read[x:T] -> value.write[x+1] -> RUN )+VarAlpha. ||SUPERMARKET = (east:TURNSTILE || east:TURNSTILE

|| south:TURNSTILE || {east,west,display,south}::value:VAR) /{go/{ east, west, south}.go, end/{east, west, south}.end}.

Hình 4.12. Tiến trình SUPERMARKET.

LTS của tiến trình SUPERMARKET có các thành phần được xác định như sau:

- Tập các trạng thái Q:

Vì tiến trình SUPERMARKET là sự kết hợp của các tiến trình thành phần

Một phần của tài liệu Đặc tả và kiểm chứng thiết kế của hệ thống tương tranh (Trang 34)