Upload
duongdtran
View
91
Download
2
Embed Size (px)
Citation preview
Trường Đại Học Công Nghệ Thông Tin
Khoa Kỹ Thuật Máy Tính
HỆ THỐNG THỜI GIAN THỰC
Lớp: CE312.F11
GV : Phạm Văn Phước
Seminal Chương 5
ĐỒNG BỘ HÓA VÀ GIAO TIẾP
DỰA TRÊN BIẾN CHIA SẺ
1
Danh Sách Thành Viên Nhóm:
Trần Đại Dương
Nguyễn Viết Nam
Nguyễn Văn An
Nguyễn Văn Thể Mỹ
Phan Trần Như Ngọc
Võ Dương Quang
11520537
11520241
11520003
11520234
11520253
11520709
2
Mục tiêu
• Hiểu các yêu cầu cần thiết cho việc đồng bộ hóa và
giao tiếp dựa trên biến chia sẻ
– Busy waiting, semaphores, monitors, conditional
critical regions, deadlock, livelock, … trong OS
• Hiểu các phương thức đồng bộ hóa trong Java
3
4
Nội Dung Chương 5
5.1 Độc quyền truy xuất và đồng bộ hóa điều kiện
5.2 Busy waiting
5.3 Suspend and Resume
5.4 Semaphore
5.5 Conditional Critical Region
5.6 Monitors
5.7 + 5.8 POSIX Mutex và Condition Variables
5.9 Phương thức đồng bộ trong Java
5.10 Chia sẻ bộ nhớ đa xử lý
5.11 Hệ thống nhúng rà soát đơn giản
*Tổng kết
• Tính chính xác của một chương trình song song
phụ thuộc vào việc đồng bộ hóa và giao tiếp giữa
các tác vụ
• Đồng bộ hóa: là việc thỏa mãn các ràng buộc
xen giữa các hành động của các tác vụ
• Giao tiếp (truyền thông): là việc truyền thông
tin từ tác vụ này tới tác vụ khác
• Giao tiếp giữa các tác vụ thường dựa trên biến
chia sẻ hoặc truyền thông điệp
Đồng Bộ Hóa Và Giao Tiếp
6
Biến chia sẻ
• Biến chia sẻ: là đối tượng mà nhiều tác vụ có
thể cùng truy cập
– “Bạn đường của vùng nhớ chia sẻ”
– Vấn đề về tính tin cậy và tính an toàn
• Ví dụ: xem xét X := X + 1
– LOAD R1, X ; Nạp giá trị của X vào R1
– INC R1 ; Tăng giá trị của R1 lên 1 giá trị
– STORE R1, X ; Lưu giá trị của R1 vào X
• Tính “atomic” của phép toán cập nhật X?
7
Miền găng (Critical region)
• Miền găng: là một chuỗi các câu lệnh phải
thực thi để đảm bảo tính “atomic”
• Độc quyền truy xuất (Mutual exclusion):
là giải pháp bảo vệ miền găng
• Ví dụ: A thực hiện X := X + 1
B thực hiện X := X đồng thời với A
8
Đồng bộ hóa điều kiện
• Đồng bộ hóa điều kiện: là một đòi hỏi quan trọng và
cần thiết khi một tác vụ muốn thực hiện một hành
động một cách hợp lý chỉ khi một tác vụ khác đạt
được một số trạng thái nhất định
– Thực hiện “Độc quyền truy xuất”
• Ví dụ: bài toán Người sản xuất (A)/ Người tiêu dùng
(B)
– A không được sản xuất khi kho đầy hàng
– B không được tiêu dùng khi kho hết hàng
• Liệu có cần thực hiện độc quyền truy xuất trong bài
toán ở trên?9
Busy waiting
• Busy waiting: là một giải pháp việc đồng bộ
hóa điều kiện
– Sử dụng tối đa CPU
task_a() {
…
while (flag == 0);
…
}
task_b() {
…
flag = 1;
…
}
11
Busy waiting – Biến cờ hiệu (flag)
while(1) {
while(flag == 1); // Đang truy xuất
flag = 1;
critical_region();
flag = 0;
non_critical_region();
}
Điều gì xảy ra khi “flag = 1;” bị tạm hoãn?
12
Busy waiting – Chơi theo lượt
while(TRUE) {
while(turn == 1);
critical_region();
turn = 1;
non_critical_region();
}
while(TRUE) {
while(turn == 0);
critical_region();
turn = 0;
non_critical_region();
}
Điều gì xảy khi khi một tác vụ không vào miền găng?
13
Busy waiting – Peterson
while(TRUE) {
flag[i] = 1;
turn = j;
while(turn == j && flag[j] == 1);
critical_region();
flag[i] = 0;
non_critical_region();
}
14
Ex:
Dual Core
T
1
T
2
Dual Core
T
1
T
2
Dual Core
Done!70%
T
1
T
2
Dual Core
Done!100%
Suspend and Resume
Data Race
Condition
21
• Nó được phát triển bởi Dijkstra (1968) và có
2 ưu điểm sau:
– Đơn giản hóa cơ chế đồng bộ hóa.
– Xóa bỏ những thứ cần thiết cho vòng lặp
busy-waiting
Semaphore
24
Semaphore
• Semaphore là biến số nguyên không âm, nó được điềukhiển bởi 2 thủ tục. Những thủ tục này được goi là wait & signal
• Wait - Nếu giá trị semaphore (S) >= 0 thì giảm giá trịxuống 1 đơn vị. Nếu không thì delay cho đến khi S lớn hơn 0.
• Signal – Tăng giá trị của S lên 1
Wait Signal
Semaphore
Semaphore thông thường được gọi là Counting Semaphores
Những toán tử này dùng để tăng và giảm biến Counting Semaphores25
Semaphore - Binary and
quantity semaphores
Binary Semaphore: S bằng 0 hoặc 1
Quantity semaphore: S bằng một tham số
Ex:
29
Conditional Critical Region
• Conditional Critical Region (CCR) là 1 nỗ lực để
khắc phục 1 số vấn đề liên quan tới semaphores.
• Miền găng điều kiện cung cấp điều kiện đồng bộ hoá
cho các miền găng.
• Các biến dùng chung được nhóm lại thành các vùng
được đặt tên & được xem như là tài nguyên.
region protected_variable, when Boolean_condition do
begin
…
end ;
31
Conditional Critical Region
• Process muốn truy cập vào region thì điều kiện phải được kiểm
tra. Nếu không thoả thì process dừng lại & process khác được tiếp
tục. Var db: shared; rc: integer;
Reader process
Region db
begin
rc := rc + 1;
end;
Read database
Region db
begin
rc := rc - 1;
end;
Writer process
Region db when rc = 0
begin
Write database
end; 32
Monitors
• Vấn đề chính của miền găng điều kiện là chúng có thể
phân tán trong suốt chương trình.
• Với monitor, các miền găng được viết như thủ tục &
được đóng gói lại thành 1 module duy nhất gọi là
monitor.
• Monitor gồm 1 khai báo các biến cục bộ của nó, 1 tập các
thủ tục monitor & 1 thủ tục khởi tạo trạng thái monitor.
35
MonitorsMonitor <tên monitor>
{
khai báo các biến được chia sẻ
procedure P1 (…)
{
…
}
procedure P2 (…)
{
…
}
.
.
procedure Pn (…)
{
…
}
{
mã khởi tạo
}
}
36
Monitors
• Miền găng là cố định & được xác định sẵn trong các thủ
tục monitor => monitor có tính cấu trúc hơn semaphore.
• Những biến cục bộ của monitor có thể được truy xuất chỉ
bởi những thủ tục cục bộ.
• Chỉ một quá trình tại một thời điểm có thể được kích hoạt
trong monitor
• Monitor là một cải tiến so với CCR bởi vì tất cả các code
truy cập dữ liệu dùng chung đều được tập trung.
37
Monitors
• Monitor vẫn cần điều kiện đồng bộ.
• Đó là biến điều kiện (condition variable), được thực thi bởi
2 toán tử được gọi là wait & signal (tương tự như trong
semaphore).
• Người lập trình có thể định nghĩa một hay nhiều biến kiểu
condition:
condition x;
x.wait(): quá trình gọi thao tác này được tạm dừng
cho đến khi quá trình khác gọi x.signal();
x.signal(): thực thi tiếp quá trình tạm dừng.
38
MonitorsRw: monitor
Var rc: integer;
busy: boolean;
toread, towrite: condition;
procedure startread
begin
if busy then
toread.wait();
rc := rc + 1;
toread.signal();
end;
procedure endread
begin
rc := rc - 1;
if rc = 0 then
towrite.signal();
end;
procedure startwrite
begin
if busy or rc != 0
then towrite.wait();
busy := true;
end;
procedure endwrite
begin
busy := false;
toread.signal() or
towrite.signal();
End
39
Monitors
Reader process
Rw.strartread;
Read database;
Rw.endread;
Writer process
Rw.startwrite;
Write database;
Rw.endwrite;
Rw: monitor
Var rc: integer;
busy: boolean;
toread, towrite: condition;
procedure startread
begin
if busy then
toread.wait();
rc := rc + 1;
toread.signal();
end;
procedure endread
begin
rc := rc - 1;
if rc = 0 then
towrite.signal();
end;
procedure startwrite
begin
if busy or rc # 0
then toread.wait();
busy := true;
end;
procedure endwrite
begin
busy := false;
toread.signal() or
towrite.signal();
end
40
Monitors
Hạn chế của monitor
• Không đối phó tốt với điều kiện đồng bộ, phải dùng
đến semaphore cấp thấp, như độ ưu tiên (primitive).
• Cơ cấu bên trong của nó vẫn khó hiểu để sử dụng các
biến điều kiện.
41
Mutex
• Tương tự semaphore, MUTEX cung cấp cách
thức loại trừ tương hỗ (mutual exclusion) giữa
các pthread
43
Mutex• Tạo và khởi tạo một biến mutex
• Một vài thread thử khóa mutex
• Chỉ một thread thành công và thread đó sỡ hữu
mutex
• Thread sở hữu thực hiện một vài tập các hành
động
• Thread sở hữu mở khóa mutex
• Một thread khác giành được mutex và lặp lại
quá trình trên
• Cuối cùng hủy mutex44
Mutex
• Khai bao và khơi tạo
#include <pthread.h>
pthread_mutex_t mutex;
mutex = PTHREAD_MUTEX_INITIALIZER;
Hoặc dùng hàm pthread_mutex_init()
int pthread_mutex_init(
pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutexattr);
45
Mutex
• Thao tác
int pthread_mutex_lock(
pthread_mutex_t *mutex);
int pthread_mutex_unlock(
pthread_mutex_t *mutex);
int pthread_mutex_destroy(
pthread_mutex_t *mutex);
46
Condition Variables
• Hoạt động theo cơ chế wait-signal, cho phép một
hoặc nhiều thread chờ một sự kiện nào đó phát
sinh, khi có sự kiện thì các thread đang chờ sẽ
được kích hoạt để thực thi
• Phải dùng kèm với mutex
47
Condition Variables
• Khai báo và khởi tạo dữ liệu/biến toàn cục cần đồng
bộ hóa (ví dụ “count”).
• Khai báo và khởi tạo biến điều kiện.
• Khai báo và khởi tạo mutex liên quan.
• Tạo thread A và B để làm việc
Thread chính
48
Condition Variables
Làm việc tới khi một điều kiện nhất định phải xảy ra.(ví dụ khi
biến count đạt được một giá trị cụ thể nào đấy)
Khóa mutex liên quan và kiểm tra giá trị của biến toàn cục.
Gọi thủ tục pthead_cond_wait() để thực hiện việc ngăn chặn đợi
tín hiệu từ thread B. Chú ý rằng, một lời gọi tới hàm
pthead_cond_wait() sẽ tự động mở khóa cho mutex liên quan để
nó có thể được sử dụng bởi thread B.
Khi đã nhận được tín hiệu,thread A sẽ “wake up”. Mutex sẽ tự
động bị khóa.
Mở khóa mutex.
Tiếp tục
Thread A49
Condition Variables
Làm việc
Khóa mutex liên quan.
Thay đổi giá trị của biến toàn cụng để thread A chờ.
Kiểm tra giá trị của biến toàn cục mà thread A chờ. Nếu nó thỏa
mãn điều kiện mong muốn, tín hiệu cho thread A.
Mở khóa mutex.
Tiếp tục
Thread B
50
Condition Variables
• Khai báo và khởi động #include <pthread.h>
pthread_cond_t dk;
dk = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(
pthread_cond_t *cond, pthread_condattr_t *cond_attr);
52
Condition Variables
• Thao tácint pthread_cond_signal(
pthread_cond_t *cond);
int pthread_cond_broadcast(
pthread_cond_t *cond);
int pthread_cond_destroy(
pthread_cond_t *cond);
int pthread_cond_wait(
pthread_cond_t *cond, pthread_mutex_t *mutex);
53
Synchronized methods in Java
-Trong Java, có một lock (khóa) có liên quan với mỗi đối
tượng. Khóa này không thể truy cập trực tiếp bởi các ứng
dụng, nhưng nó bị ảnh hưởng bởi:
Phương thức Modifier Synchronized;
Một khối đồng bộ hóa.
- Khi một phương thức được đặt tên với synchoronized
modifier, truy cập tới phương thức này có thể chỉ tiến hành
một lần Lock liên quan đến đối tượng đã giành được
(obtained)
55
Synchronized methods in Java
public class SharedInteger {
private int theData;
public SharedInteger(int initialValue) {theData = initialValue;
}
public synchronized int read() {return theData;
}
public synchronized void write(int newValue) {theData = newValue;
}
public synchronized void incrementBy(int by) { theData = theData + by;
}}
SharedInteger myData = new SharedInteger(42);
56
Synchronized methods in Java
- Khối đồng bộ hóa cung cấp một cơ chế theo đó một khối
có thể được đặt tên như là đồng bộ (synchronized).
- Các từ khóa synchronized như một tham số một đối tượng
có khóa nó cần phải có được trước khi nó có thể tiếp tục.
Do đó, phương thức đồng bộ này là hiệu quả thực hiện
được như sau:
57
Waiting and notifying
(Đợi và thông bao)
- Để nhận được đồng bộ hóa có điều kiện đòi hỏi các
phương thức cung cấp trong lớp đối tượng được
xác định trướcpublic void wait() throws
InterruptedException;
public void notify();
public void notifyAll();
58
• wait() cho thread gọi nó từ bỏ monitor và ngủ cho tới
khi thread khác đi vào monitor và gọi notify()
• notify() đánh thức một thread đã gọi wait() trên cùng
đối tượng
• notifyAll() đánh thức tất cả các thread đã gọi wait()
trên cùng đối tượng. Một trong số chúng sẽ được cho
phép truy cập
• Nếu gọi mà không cần khóa, ngoại lệ IllegalMonitor-
StateException được ném
Waiting and notifying
(Đợi và thông bao)
59
Biến điều kiện:
• Không có các biến điều kiện rõ ràng
• Một chủ đề thường đánh thức nên đánh giá điều kiện mà
nó đang chờ đợi.public class BoundedBuffer {
private int buffer[];
private int first;
private int last;
private int numberInBuffer = 0;
private int size;
public BoundedBuffer(int length) {
size = length;
buffer = new int[size];
last = 0;
first = 0;
};
Waiting and notifying
(Đợi và thông bao)
60
The readers-writers problem
(Vấn đề độc giả-nhà văn)
Giải pháp cho vấn đề độc giả-nhà văn sử dụng tiêu chuẩn
monitor yêu cầu bốn thủ tục giám sát :
- startRead, stopRead, startwrite và stopwrite.
public class ReadersWriters
{
private int readers = 0;
private int waitingWriters = 0;
private boolean writing = false;
62
Inheritance and synchronization
(Thừa kế và đồng bộ hóa)
Ví dụ, xem xét các bộ đệm bị chặn trước đó trong phần này.
Với Java, code để kiểm tra các điều kiện (BufferNotFul1 và
BufferNotEmpty) là nhúng trong các phương thức.
65
The Java memory model
(Mô hình bộ nhớ trong Java)
• Với hai hành động A và B, kết quả của hành động A
là có thể nhìn thấy hành động B nếu có một
happens-before quan hệ giữa chúng. Các điều kiện
sau xác định các mối quan hệ:
Nếu A và B là trong cùng một thread và A đi trước B
trong chương trình gọi thì A happens-before B.
Một hành động mở khóa monitor happens-before
tất cả hành động lock tiếp theo trên cùng monitor;
Ghi vào một biến động 'biến V happens-before tất
cả các hoạt động tiếp theo đọc từ V trong bất kỳ
Thread nào; 69
The Java memory model
(Mô hình bộ nhớ trong Java)
Một một hành động mà bắt đầu một Thread happens-before
hành động đầu tiên của thread nó bắt đầu;
Hành động cuối cùng của một Thread happens-before bất
kỳ hành động bất kỳ Thread khác xác định rằng nó đã chấm
dứt
Các ngắt của một Thread T happens-before bất kỳ Thread
đó phát hiện T đã đượcngắt
Nếu A happens-before B và B happens-before -C, sau đó
A happens-before C
70
72
A) Trong phần 4.8, một hệ thống nhúng đơn giản đã
được giới thiệu và một giải pháp đồng thời đã được
đề xuất. Các giải pháp bằng Ada bây giờ được giới
thiệu như là một ví dụ minh họa cho giao tiếp với
giao diện điều khiển của hệ điều hành. Ta cần nhớ lại
rằng cấu trúc của bộ điều khiển như sau:
Simple embedded system revisited
73
Simple embedded system revisited
// Khai báo hàm và thư viện cần thiết
with Data_Types; use Data_Types;
with IO; use IO;
with Control_Procedures; use Control_Procedures;
// Mở đầu là các phần đặc tả
procedure Controller is
task Temp_Controller; // Tác vụ Điều khiển nhiệt độ
task Pressure_Controller; // Tác vụ Điều khiển áp lực
74
Simple embedded system revisited
task body Temp_Contro1ler is
TR : Temp_Reading; HS :
Heater_Setting;
begin
loop
Read(TR);
Temp#Convert(TR,HS);
….
….
end Controller;
// Phần thân
75
Simple embedded system revisited
with Data_Types; use Data_Types;
package I0 is
// Thủ tục trao đổi dữ liệu với môi trường
--procedures for data exchange with the environment
procedure Read(TR: out Temp_Reading); ~— from DAC
procedure Read(PR : out Pressure_Reading); ~— from DAC
procedure Write(HS : Heater_Setting); —— to switch.
procedure Write(PS Pressure_Setting); -- to DAC
procedure Write(TR : Temp_Reading); —— to console
procedure Write(PR Pressure_Reading); *~ to console
end IO;
B) Thủ tục trao đổi dữ liệu với môi trường:
76
Simple embedded system revisited
C) Phần thân của các giao thức I/O bây giờ có thể được hoàn
chỉnh. Các dữ liệu được gửi đến giao diện điều khiển được
lưu trữ trong một màn hình (trong trường hợp này bằng cách
sử dụng một đối tượng được Ada bảo vệ). Nhiệm vụ giao
diện điều khiển sẽ gọi vào để có được những dữ liệu mới.
77
Simple embedded system revisited
Lúc này chương trình hoàn chỉnh được biểu diễn như sau:
// Khai báo và đặc tảpackage body I0 is
task Console;
protected Console_Data is
procedure Write(R : Temp_Reading);
procedure Write(R : Pressure_Reading);
entry Read(TR : out Temp_Reading;
PR : out Pressure_Reading);
private
Last_Temperature : Temp_Reading;
Last_Pressure :Pressure_Reading;
New_Reading : Boolean := False;
end Console_Data;
78
Simple embedded system revisited
// Phần các thủ trao đổi với môi trường-- procedures for data exchange with the environment
procedure Read(TR : out Temp_Reading) is separate; —— from DAC
procedure Read(PR : out Pressure_Reading) is separate; —— from DAC
procedure Write(HS : Heater_Setting) is separate; —— to switch,
procedure Write(PS : Pressure_Setting) is separate; —v to DAC
79
Simple embedded system revisited
//Phần thân làm nhiệm vụ đọc giá trịtask body Console is
TR : Temp_Reading;
PR : Pressure_Reading;
begin
loop
Console_Data.Read(TR, PR);
// Hiển thị quá trình đọc mới
—— Display new readings
end loop;
end Console;
80
Simple embedded system revisited
protected body Console_Data is
procedure Write(R : Temp_Reading) is
begin
Last_Temperature := R;
New_Reading := True;
end Write;
procedure Write(R : Pressure_Reading) is
begin
Last_Pressure := R;
New_Reading := True;
end Write;
entry Read(TR : out Temp_Reading;
PR : out Pressure_Reading)
when New_Reading is
begin
TR := Last_Temperature;
PR := Last_Pressure;
New_Reading := False;
end Read;
end Console_Data;
//Phần xử lý chính
81
Simple embedded system revisited
//Thủ tục xuấtprocedure Write(TR : Temp_Reading) is
begin
Console_Data.Write(TR);
end Write; —— to screen
procedure Write(PR : Pressure_Reading) is
begin
Console_Data.Write(PR);
end Write; —— to screen
end IO;
82
Simple embedded system revisited
Link tìm hiểu về Ada:http://www.hvaonline.net/hvaonline/readingRoom/item/1643.hva;jsessionid=72AC
4AB98D9CE5113200E78DAECE7FEB
84
Quá trình tương tác yêu cầu phải có sự đồng thời giữa hệ điều hành
và ngôn ngữ lập trình để hỗ trợ đồng bộ hóa và truyền thông nội
bộ. Truyền thông có thể dựa trên một trong hai: biến chia sẻ hoặc
truyền thông điệp. Chương này quan tâm với các biến được chia sẻ,
cho thấy nhiều khó khăn trong đồng thời và đồng bộ hóa loại trừ
tương hỗ cần thiết để đối phó với những khó khăn đó. Trong cuộc
thảo luận này, các từ ngữ dưới đây đã được giới thiệu:
85
*Critical section : đoạn mã phải thực hiện theo loại trừ tương hỗ
*Producer - consumer system: hai hoặc nhiều tác vụ trao đổi dữ liệu
thông qua một bộ đệm hữu hạn
*Busy waiting: một tác vụ liên tục kiểm tra điều kiện để xem tiến
trình có thể được tham gia vào quá trình xử lý hay không
*Livelock : một điều kiện lỗi trong đó một hoặc nhiều tác vụ đều bị
cấm hoạt động trong quá trình dung tăng lên mỗi chu kỳ xử lý.
86
Việc cung cấp một semaphore sơ khai có kết quả từ việc đưa ra một
trạng thái mới cho một tác vụ; cụ thể là, bị đình chỉ (suspended.).
Nó cũng cung cấp hai điều kiện lỗi mới:
*Deadlock: một tập hợp các tác vụ trì hoãn mà không thể tham gia
vào quá trình xử lý
*Indefinite postponement: một nhiệm vụ không có khả năng tiến
hành như nguồn tài nguyên không được thực hiện có sẵn dùng cho
nó.
87
Semaphores có thể bị đánh giá là hiệu suất thấp và dễ bị lỗi trong khi
sử dụng. Sau một thời gian phát triển, 5 cấu trúc tốt hơn được giới
thiệu:
- Conditional critical regions
- A monitors
- Mutexes
- Protected objects
- Synchronized methods
88
Monitor là một tính năng giao thức quan trọng. Chúng bao gồm một
mô-đun, nhập liệu được đảm bảo là thuộc loại trừ tương hỗ. Trong
cấu trúc của một monitor, một tác vụ có thể tự dừng nếu không đủ
điều kiện để tiếp tục xử lý. Việc đình chỉ này được thực hiện bằng
cách sử dụng một biến điều kiện. Khi một công việc đình chỉ được
đánh thức (bởi một hoạt động tín hiệu trên biến điều kiện), điều này
đảm bảo không dẫn đến trường hợp hai tác vụ hoạt động trong mô-
đun cùng một lúc.