TRƯỜNG ĐẠI HỌC THUỶ LỢI KHOA CÔNG NGHỆ THÔNG TIN BỘ MÔN CÔNG NGHỆ PHẦN MỀM Bài giảng LẬP TRÌNH PHÂN TÁN Hà Nội 09/2021 TRƯỜNG ĐẠI HỌC THUỶ LỢI Khoa Công Nghệ Thông Tin Bộ Môn Công Nghệ Phần Mềm LẬP TR[.]
Trang 1TRƯỜNG ĐẠI HỌC THUỶ LỢI
KHOA CÔNG NGHỆ THÔNG TIN
BỘ MÔN CÔNG NGHỆ PHẦN MỀM
Bài giảng
LẬP TRÌNH PHÂN TÁN
Hà Nội - 09/2021
Trang 2TRƯỜNG ĐẠI HỌC THUỶ LỢI
Khoa Công Nghệ Thông Tin
Trang 3Giảng viên: Lê Nguyễn Tuấn Thành Email: thanhlnt@tlu.edu.vn
Trang 4Giới thiệu chung
Programming
▪ Số tín chỉ: 3 (LT: 2, TH/BT/TL: 1)
▪ Số tiết: 30 - Lý thuyết và 15 - Thực hành
2
Trang 5Mục tiêu môn học
năng cho lập trình đồng thời, lập trình song song và lập trình phân tán
▪ Cung cấp kiến thức nền tảng để phát triển ứng dụng đồng thời và phân tán
3
Trang 6Terminology
▪ Concurrent programming
▪ Thread, Process, Locks, Safety, Liveness,
▪ Deadlock, Livelock, Resource starvation,
Trang 7Nội dung
môn học
▪Bài 1: Những khái niệm cơ sở
▪Bài 2: Bài toán loại trừ lẫn nhau
▪Bài 3: Những cơ sở đồng bộ hóa
▪Bài 7: Kiểu thứ tự thông điệp
▪Bài 8: Bài toán lựa chọn người lãnh đạo 5
Trang 8Yêu cầu với sinh viên
▪ Tham dự lớp và nghe giảng đầy đủ
▪ Thảo luận, làm bài tập trên lớp và Piazza (cộng điểm)
▪ Website môn học: sites.google.com/site/cse423fall2018/
▪ Lớp học ảo:
▪ Cách đánh giá:
6
Trang 9Tài liệu tham khảo
▪ Concurrent and Distributed Computing in Java, Vijay K Garg, University of Texas, John Wiley & Sons, 2005
▪ Xử lý song song và phân tán, Đoàn văn Ban, Nguyễn Mậu Hân, Nhà
xuất bản Khoa học và Kỹ thuật, 2009.
7
Trang 10Giảng viên: Lê Nguyễn Tuấn Thành Email: thanhlnt@tlu.edu.vn
1
Trang 11NỘI DUNG
2
Bài giảng có sử dụng hình vẽ trong cuốn sách “Concurrent and Distributed Computing in Java, Vijay K
Garg, University of Texas, John Wiley & Sons, 2005”
Trang 12Phần 1.
Thuật ngữ
3
Trang 13Thuật ngữ (1)
▪ Tính toán tuần tự (sequential computing)
▪ Tại một thời điểm chỉ thực hiện được một tính toán
▪ Chỉ có một luồng điều khiển chính
▪ Hệ thống đơn nhiệm (single-tasking systems)
▪ Hệ thống đa nhiệm (multitasking systems)
▪ Time-slicing
4
Tại sao phải tính toán đồng thời / song
song?
Trang 14Thuật ngữ (2)
▪Tính toán đồng thời / song song (concurrent
/ parallel computing): Mô hình chia sẻ bộ nhớ
▪ Tại một thời điểm có thể thực hiện nhiều tính toán
▪ Bao gồm nhiều “chương trình” chạy trên một hoặc
nhiều bộ vi xử lý
▪ Giao tiếp với nhau bằng cách sử dụng bộ nhớ chia sẻ
▪ Một “chương trình” bất kỳ luôn biết được trạng
thái toàn cục của toàn bộ hệ thống
5
Trang 15Minh họa:
Hệ thống song song
Trang 16Giả sử: 1 người ≈ 1 Processor
Trang 17Thuật ngữ (3)
▪Tính toán phân tán (distributed computing)
▪ Hệ thống phân tán chứa nhiều bộ xử lý được kết nối với nhau bởi một mạng truyền thông
▪ Các bộ vi xử lý giao tiếp với nhau bằng cách gửi và nhận các thông điệp, thông qua các kênh truyền thông (pipe, socket)
▪ Không có bộ xử lý nào biết được trạng thái toàn cục của toàn bộ hệ thống phân tán
8
Trang 18Minh họa:
Hệ thống phân tán
Trang 1910
Trang 20của một chương trình đang chạy, có không gian bộ nhớ riêng, gồm:
▪ Ngăn xếp gồm các biến địa phương và
các bản ghi kích hoạt lời gọi hàm
11
Các luồng trong cùng một tiến trình chia sẻ tài nguyên (bộ nhớ, files,…)
Luồng “gọn nhẹ" hơn so với tiến trình và tốn ít phụ phí hơn để tạo và
huỷ luồng so với khởi động một tiến trình mới.
Trang 2112
Trang 22Minh hoạt luồng 13
Trang 23Thách thức của các
chương trình đồng thời
Làm sao để đồng bộ việc thực thi của các tiến trình/luồng khác nhau và cho phép chúng giao tiếp với nhau ?
14
Trang 24▪ Giả sử chương trình có 2 luồng:
1 Luồng P bao gồm 2 câu lệnh p1, được theo sau bởi p2
2 Luồng Q bao gồm 2 câu lệnh q1, được theo sau bởi q2
▪ Hai luồng bắt đầu thực thi tại vị trí của con trỏ điều kiển (control pointer), lúc đầu trỏ tới p1 và q1
▪ Giả sử các câu lệnh không thực hiện việc chuyển điều khiển khi đang thực thi
▪ Tôn trọng sự thực thi tuần tự của mỗi tiến trình
▪ Do đó p2 không thể thực thi trước p1 !
15
Interleaving
Trang 25Race condition
Giá trị của n là bao nhiêu khi p, q thực thi xong ?
Trang 2617
Trang 27Có hai cơ chế để bảo vệ một khối mã lệnh khỏi việc truy cập đồng thời
• Từ khoá synchronized
• Lớp ReentrantLock (từ Java SE 5.0)
Trang 28Concurrency is Hard to
Test and Debug (1)
▪It’s very hard to discover race conditions using testing
▪ Each time you run a program containing a race condition, you may get different behavior !
on the relative timing of events that are strongly influenced by the environment
scheduling decisions, variations in processor clock speed, etc
19
Trang 29Concurrency is Hard to
Test and Debug (2)
1. heisenbugs, which are nondeterministic and hard
to reproduce,
2. bohrbug, which shows up repeatedly whenever
you look at it
▪ Almost all bugs in sequential programming are
bohrbugs
▪ A heisenbug may even disappear when you try to look
at it with println or debugger !
▪ The reason is that printing and debugging are so much slower than other operations, often 100-1000x slower, that they dramatically change the timing of operations, and the interleaving
20
Trang 30Phần 2.
Luồng trong Java
21
Trang 31Tạo luồng bằng cách
Trang 32Tạo luồng bằng cách cài
Trang 33Các trạng thái của luồng
trong Java
Trang 34Cơ chế Join (1)
hoàn thành việc thực thi
Trang 36Lập lịch trình luồng
▪Nếu cả hai luồng đều có thể chạy, luồng nào
sẽ được chọn để chạy bởi hệ thống?
▪ Phụ thuộc vào độ ưu tiên và chính sách lập lịch của
hệ thống
▪ Thay đổi độ ưu tiên của luồng sử dụng setPriority
và lấy ra độ ưu tiên hiện tại sử dụng getPriority
▪ MIN_PRIORITY (1), MAX_PRIORITY (10), NORM_PRIORITY (5): 3 hằng số nguyên được định nghĩa trong lớp Thread
▪Daemon thread: luồng chạy ngầm
27
Trang 37Tài liệu tham khảo
▪ Concurrent and Distributed Computing in Java, Vijay K Garg, University of Texas, John Wiley & Sons, 2005
▪ Xử lý song song và phân tán, Đoàn văn Ban, Nguyễn Mậu Hân, Nhà
xuất bản Khoa học và Kỹ thuật, 2009
28
Trang 39Bài giảng có sử dụng hình vẽ trong cuốn sách “Concurrent and Distributed Computing in Java, Vijay K
Garg, University of Texas, John Wiley & Sons, 2005”
Trang 40Thách thức trong các
chương trình đồng thời
▪ Đồng bộ sự thực thi của các luồng khác nhau
thông qua bộ nhớ chia sẻ
3
Trang 42“Lost update” Problem (1)
▪Nguyên nhân: Race condition
▪Xét tình huống:
▪ Có một biến chia sẻ x với giá trị ban đầu là 0
▪ Có hai luồng T0 và T1 đều tăng giá trị của x lên 1
▪ Liệu giá trị của x sau khi thực thi T0 và T 1 sẽ là 2?
5
Trang 43“Lost update” Problem (2)
Đọc giá trị x vào một thanh ghi (giá trị được đọc: 0)
Tăng thanh ghi (1)
Ghi giá trị trong thanh ghi ngược lại x (x=1)
Đọc giá trị x vào một thanh ghi (giá trị được đọc: 1)
Tăng thanh ghi (2) Ghi giá trị trong thanh ghi ngược lại x (x=2)
Trang 44Tăng thanh ghi (1)
Đọc giá trị x vào một thanh ghi (giá trị được đọc: 0)
Tăng thanh ghi (1)
Ghi giá trị trong thanh ghi ngược lại x (x=1)
Ghi giá trị trong thanh ghi ngược lại x (x=1)
Trang 45Region - CR ) hay phần quan trọng (Critical Section - CS )
▪ Cho ví dụ về CS ???
8
Trang 46Bài toán loại trừ lẫn
nhau (Mutex)
▪Là bài toán nhằm đảm bảo rằng khu vực quan
trọng (CR/CS) của một luồng phải được thực
thi theo một cách nguyên tử
▪Là một trong những bài toán căn bản nhất trong tính toán đồng thời
9
Trang 47Giao diện cho Bài toán
Mutex
▪Định nghĩa giao diện Lock để đồng bộ việc
truy cập khu vực quan trọng (CR/CS) của các
luồng
10
Trang 48releaseCS(j)
11
Trang 49Phần 2
Giải pháp cho
Bài toán Mutex
Busy-waiting solutions within a loop
12
Trang 50Trường hợp
2 luồng
13
Trang 51Thuật toán 1
▪Sử dụng một biến chia sẻ giữa 2 luồng,
openDoor kiểu boolean được khởi tạo là true
▪requestCS: luồng đợi cho đến khi biến
openDoor có giá trị true
▪Khi giá trị của biến này là true, luồng có thể đi
vào CS, sau đó nó đặt lại giá trị của openDoor
thành false
▪releaseCS: luồng đặt lại giá trị của biến
openDoor là true
14
Trang 5215
Trang 53▪ Luồng thứ 2 lúc này kiểm tra giá trị
lệnh while để đi vào CS !
▪ Cả hai luồng bây giờ đều có thể đặt
openDoor thành false và cùng đi vào CS
▪ Do đó, cài đặt 1 vi phạm sự loại trừ lẫn nhau !
16
Trang 54▪Trong cài đặt 1, biến chia sẻ openDoor không
lưu lại luồng nào đã cập nhật nó thành false
▪Cài đặt 2 giải quyết vấn đề này bằng cách sử dụng 2 biến chia sẻ wantCS [0] và wantCS[1]
17
Thuật toán 2:
Dẫn đến Deadlock
Trang 5518
Trang 56nó thành true và rơi vào
vòng lặp đợi vô hạn do đều chờ luồng kia đặt bit
wantCS thành false!
▪DEADLOCK !
19
Trang 57▪ Thread 1: locks resource A, waits for resource B
▪ Thread 2: locks resource B, waits for resource A
20
Trang 58▪Một luồng sẽ đợi đến lượt nó để đi vào CS
Khi thoát ra khỏi CS, nó đặt lại giá trị biến
turn thành 1-i
21
Trang 60▪ Do đó, sau khi luồng T 0 thoát khỏi CS,
T 0 không thể đi vào CS nữa cho đến khi
luồng T 1 đi vào CS và thay đổi lại giá
trị của biến turn !
▪ Nếu T 1 không quan tâm tới việc đi vào
CS, thì T0 sẽ bị tắc lại vô hạn do phải
đợi P 1 !
23
Trang 61Thuật toán Peterson (1)
▪ Kết hợp 2 cách tiếp cận trước để giải quyết bài toán mutex trong một hệ thống có 2 luồng hoạt động đồng thời
2 cờ/bit, wantCS[0] và wantCS[1] , như
cài đặt 2, và một biến turn như trong cài đặt 3
24
Trang 632. Tiến độ (progress)
▪ Nếu một hoặc hai luồng đang
cố gắng đi vào CS và không có luồng nào bên trong CS, thì ít nhất một luồng sẽ đi vào CS thành công
(starvation-freedom)
▪ Nếu một luồng đang cố gắng
đi vào CS, thì cuối cùng nó phải được đi vào CS
26
Trang 64Trường hợp
N luồng (N>2)
27
Trang 65Thuật toán Bakery của
Trang 66Thuật toán Bakery của
Lamport (2)
▪ Một luồng T i phải đi qua 2 bước chính trước khi có
thể đi vào CS
1. Bước 1: được gọi là doorway
▪ T i được yêu cầu chọn một số
▪ T i đọc số của tất cả những luồng khác và chọn ra một số lớn hơn số lớn nhất mà nó đọc được
2. Bước 2: kiểm tra 2 điều kiện để đi vào CS
▪ Với mỗi luồng T j khác, T i kiểm tra liệu T j có đang ở
trong doorway không Nếu T j đang ở trong doorway, thì
T i phải đợi cho T j ra khỏi doorway
Trang 68▪Thuật toán cũng thỏa
mãn điều kiện không chết
đói
▪ Do bất kỳ luồng nào đang đợi để đi vào CS thì cuối cùng nó cũng sẽ có giữ số nhỏ nhất khác 0 tại một thời điểm nào đó
▪ Khi đó, luồng này sẽ đi vào
CS thành công !
31
Trang 69▪Thuật toán luôn đòi hỏi
thời gian O(N) cho mỗi
luồng khi muốn lấy được khóa (lock) mặc dù có thể không có tranh chấp
▪Thuật toán đòi hỏi mỗi luồng sử dụng dấu thời gian (timestamps), i.e số
id, với giá trị không bị giới hạn
32
Trang 70myLock.unlock(); // Đảm bảo lock được khoá lại ngay cả
khi một ngoại lệ được ném ra
}
33
Trang 71Tài liệu tham khảo
▪ Concurrent and Distributed Computing in Java, Vijay K Garg, University of Texas, John Wiley & Sons, 2005
▪ Xử lý song song và phân tán, Đoàn văn Ban, Nguyễn Mậu Hân, Nhà
xuất bản Khoa học và Kỹ thuật, 2009
34
Trang 72Giảng viên: Lê Nguyễn Tuấn Thành Email: thanhlnt@tlu.edu.vn
1
Trang 73Synchonization primitives
Trang 74Bài giảng có sử dụng hình vẽ trong cuốn sách “Concurrent and Distributed Computing in Java, Vijay K
Garg, University of Texas, John Wiley & Sons, 2005”
Trang 75Busy-waiting problem
▪Những giải pháp ở bài trước gặp một vấn đề chung: bận chờ (busy-wait) khi sử dụng vòng lặp while
▪ Khi một luồng không thể đi vào CS, nó sẽ liên lục
kiểm tra điều kiện ở while
▪ Điều này khiến luồng không thể thực hiện các công việc khác => gây lãng phí chu trình CPU
▪ Thay vì phải kiểm tra liên tục điều kiện vào CS, nếu một luồng chỉ kiểm tra khi điều kiện này trở thành true thì sẽ không lãng phí chu trình CPU
4
Trang 76Synchnization primitives
▪Những cơ sở đồng bộ hóa giúp giải quyết vấn
đề bận chờ
▪Hai cấu trúc đồng bộ phổ biến:
R Hoare, năm 1972
5
Trang 77Phần 2.
Semaphore
Semaphores were invented by Edsger Dijkstra, 1968
6
Trang 78Source: https://www.e-reading.club/chapter.php/102147/92/Li%2C_Yao_-_Real-Time_Concepts_for_Embedded_Systems.html
Trang 798
Trang 80Thêm bản thân luồng
vào hàng đợi và khóa lại; }
value = false;
V():
value = true;
if (hàng đợi không rỗng) { Đánh thức một luồng
bất kỳ trong hàng đợi;
}
Được thực thi nguyên
tử
Được thực thi nguyên tử
Trang 8110
Trang 82Semaphore nhị phân (2)
Ví dụ cài đặt
Phương thức myWait() sẽ khóa luồng hiện tại và
chèn nó vào trong hàng đợi các luồng bị khóa
Trang 83Semaphore nhị phân
cho Bài toán Mutex
Trang 84Semaphore đếm (1)
Trang 85Semaphore đếm (2)
Ví dụ cài đặt
Tìm hiểu: java.util.concurrent.Semaphore
Trang 86Sử dụng Semaphore cho một số bài toán đồng bộ
15
Trang 87Bài toán 1: Nhà sản xuất
& Người tiêu thụ (1)
▪ Hai con trỏ inBuf và outBuf
▪ Biến count để lưu tổng số
phần tử hiện tại
16
Trang 88Bài toán 1: Nhà sản xuất
& Người tiêu thụ (2)
▪ Ngoài việc đảm bảo loại trừ lẫn nhau, bài toán này có thêm 2 rằng buộc đồng bộ có điều kiện:
1 Luồng sản xuất chỉ thực hiện thêm 1 phần tử vào cuối bộ
đệm nếu: bộ đệm không đầy
2 Luồng tiêu thụ chỉ thực hiện lấy 1 phần tử khỏi của bộ
Trang 9019
Trang 91Bài toán 2: Người đọc &
Người ghi
▪Phối hợp truy cập tới một cơ sở dữ liệu chia
sẻ giữa nhiều người đọc và nhiều người ghi
▪Các rằng buộc đồng bộ:
1. Rằng buộc đọc-ghi: Một người đọc và một người
ghi không được truy cập đồng thời vào CSDL chia
sẻ
2. Rằng buộc ghi-ghi: Hai người ghi không được truy
cập đồng thời vào CSDL chia sẻ
3. Nhiều người đọc có thể đồng thời truy cập CSDL
chia sẻ
20
Trang 93Quá trình ghi dữ liệu
endWrite()
22
ReaderjstartRead()
Quá trình đọc dữ liệu
endRead()
WriterlstartWrite()
Quá trình ghi dữ liệu
endWrite()
Starvation of a writer ?
Trang 94Bài toán 3: Bữa tối của
Triết gia (1)
Trang 95Bài toán 3: Bữa tối của
Triết gia (2)
▪N triết gia:
▪Nghĩ, Đói & Ăn
▪N cái nĩa (fork)
Trang 9625
Trang 98Bài toán 3: Tình huống Deadlock
Có khả năng mọi luồng đều bị tắc nghẽn:
fork[1 ]
fork[2 ]
fork[5 ]
fork[4 ]
fork[3 ]
Trang 99Bài toán 3: Giải pháp
fork[2 ]
fork[5 ]
fork[4 ]
fork[3
Trang 100Phần 2.
Monitor
Invented by P B Hansen and C A R Hoare, 1972
29
Trang 101Monitor (1)
toán đồng bộ luồng ở mức thấp, nhưng không thật sự hướng đối tượng
▪ Monitor ở mức cao hơn, hướng đối tượng và dễ sử dụng hơn
▪Có thể sử dụng Semaphore để cài đặt Monitor và ngược lại
30
Trang 103Monitor (2)
▪ Monitor có thể được xem như một lớp
trong lập trình đồng thời gồm: dữ liệu và
các thao tác trên dữ liệu đó
▪ Monitor hỗ trợ khái niệm phương thức
entry để đảm bảo loại trừ lẫn nhau
▪Tại một thời điểm, chỉ có nhiều nhất 1 luồng có thể thực thi trong một phương thức entry
▪ Monitor đi kèm với một hàng đợi chứa những luồng đang đợi để vào monitor
32
Trang 104▪Mỗi biến điều kiện x định nghĩa 2 thao tác:
▪wait: khoá luồng gọi và đưa vào hàng đợi của x
▪notify hoặc signal: loại một luồng khỏi hàng
đợi của x và và chèn nó vào hàng đợi
sẵn-sàng-thực-thi
33
Trang 105Ngữ nghĩa
của Monitor (1)
▪Trong Java, sử dụng từ khoá synchronized để
quy định một đối tượng là một Monitor
34
enterMonitor():
cho phép đi vào monitor nếu không có luồng nào trong đó; ngược lại, đi vào hàng đợi các luồng bị khoá;
exitMonitor():
thoát khỏi monitor và đánh thức cho luồng khác đang bị khoá
Trang 10635
Trang 107Nếu hàng đợi không rỗng, chọn một luồng tùy ý trong hàng đợi và đánh thức nó Nếu hàng đợi không rỗng, đánh thức tất cả luồng trong hàng đợi
Trang 108Luồng nào nên tiếp tục thực hiện vào thời điểm này?
Do chỉ có một luồng có thể được ở bên trong Monitor tại một thời điểm
Hai khả năng …
Trang 109Hoare-style Monitor (1)
Blocking condition variables
Luồng 0 sẽ đi vào monitor ngay lập tức
sau khi luồng 1 gọi hàm notify()