Tải bản đầy đủ

Bao cao lap trinh he thong

File locking
File locking là một phần rất quan trọng của hệ điều hành đa nhiệm. Chương trình
thường xuyên cần chia sẻ dữ liệu, thường là thông qua các tệp và điều đó rất quan
trọng là các chương trình đó có một số cách thiết lập quyền kiểm soát một tập tin. Tập
tin sau đó có thể được cập nhật một cách an toàn hoặc chương trình thứ hai có thể
dừng lại chính nó từ việc cố gắng đọc một tập tin ở trạng thái thoáng qua trong khi
một chương trình khác đang ghi vào nó. Linux có một số tính năng mà bạn có thể sử
dụng để khóa tệp. Phương pháp đơn giản nhất là một kỹ thuật để tạo ra khóa các tập
tin theo cách nguyên tử, để không có gì khác có thể xảy ra trong khi khóa đang được
tạo. Điều này mang lại cho một lập trình một phương pháp tạo các tệp được đảm bảo
là duy nhất và không thể được tạo đồng thời bởi một chương trình khác. Phương pháp
thứ hai tiên tiến hơn: nó cho phép các chương trình khóa các phần của tệp để truy cập
độc quyền. Có hai cách khác nhau để đạt được hình thức khóa thứ hai này. Chúng tôi
sẽ chỉ nhìn vào một chi tiết, vì cái thứ hai rất giống nhau - nó chỉ có giao diện lập trình
hơi khác.
Creating Lock Files
Nhiều ứng dụng chỉ cần có khả năng tạo tệp khóa cho tài nguyên. Các chương trình
khác sau đó có thể kiểm tra các tập tin để xem liệu họ có được phép truy cập tài
nguyên. Thông thường, các tệp khóa này ở một vị trí đặc biệt với tên liên quan đến tài
nguyên được kiểm soát.
Ví dụ: khi sử dụng modem, Linux sẽ tạo một tệp khóa, thường sử dụng một thư mục

trong / var /
thư mục spool.
Hãy nhớ rằng các tập tin khóa chỉ hoạt động như các chỉ số; các chương trình cần hợp
tác để sử dụng chúng. họ đang
gọi là khóa tư vấn trái ngược với khóa bắt buộc, trong đó hệ thống sẽ thực thi hành vi
khóa.
Để tạo một tệp để sử dụng làm chỉ báo khóa, bạn có thể sử dụng lệnh gọi hệ thống mở
được xác định trong fcntl.h (mà
bạn đã gặp trong một chương trước đó) với các cờ O_CREAT và O_EXCL được đặt.
Điều này cho phép bạn kiểm tra xem
tập tin đã không tồn tại và sau đó tạo nó trong một hoạt động nguyên tử duy nhất.


Lần đầu tiên bạn chạy chương trình:
$ ./lock1
Open succeeded
nhưng lần sau bạn thử, bạn sẽ nhận được
$ ./lock1
Open failed with error 17
Làm thế nào nó hoạt động
Chương trình gọi mở để tạo một tệp có tên /tmp/LCK.test, sử dụng cờ O_CREAT và
O_EXCL. Các
Lần đầu tiên bạn chạy chương trình, tập tin không tồn tại, vì vậy cuộc gọi mở thành
công. Các lệnh sau đó của chương trình không thành công vì tệp đã tồn tại. Để chương
trình thành công trở lại, bạn phải
tự xóa tệp khóa.
Trên các hệ thống Linux ít nhất, lỗi 17 đề cập đến EEXIST, một lỗi được sử dụng để
chỉ ra rằng một tệp đã tồn tại.
Số lỗi được xác định trong tệp tiêu đề errno.h hoặc, thông thường hơn, bởi các tệp
được bao gồm bởi nó. Trong này
trường hợp, định nghĩa, thực sự trong /usr/include/asm-generic/errno-base.h, đọc
#define EEXIST 17 /* File exists */
Đây là một lỗi thích hợp cho lỗi mở (O_CREAT | O_EXCL).


Nếu một chương trình chỉ cần một tài nguyên dành riêng trong một thời gian ngắn
thực hiện, thì thường được gọi là quan trọng
phần, nó sẽ tạo tập tin khóa bằng cách sử dụng lệnh gọi hệ thống mở trước khi vào
phần quan trọng và sử dụng
cuộc gọi hệ thống hủy liên kết để xóa nó sau đó, khi chương trình thoát khỏi phần
quan trọng.
Bạn có thể chứng minh làm thế nào các chương trình có thể hợp tác với cơ chế khóa
này bằng cách viết một mẫu
lập trình và chạy hai bản sao của nó cùng một lúc. Bạn sẽ sử dụng cuộc gọi getpid mà
bạn đã thấy trong
Chương 4; nó trả về định danh quy trình, một số duy nhất cho mỗi chương trình hiện
đang thực thi.

Để chạy chương trình, trước tiên bạn nên sử dụng lệnh này để đảm bảo rằng tệp khóa
không tồn tại:


$ rm -f /tmp/LCK.test2
Sau đó chạy hai bản sao của chương trình bằng cách sử dụng lệnh này:
$ ./lock2 & ./lock2
Điều này bắt đầu một bản sao của lock2 trong nền và một bản sao thứ hai chạy ở nền
trước. Đây là đầu ra:
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
Ví dụ trước cho thấy hai yêu cầu của cùng một chương trình đang hợp tác như thế
nào. Nếu bạn cố gắng
này, bạn sẽ gần như chắc chắn nhìn thấy các định danh quy trình khác nhau trong đầu
ra, nhưng hành vi chương trình sẽ
giống nhau.
Làm thế nào nó hoạt động
Với mục đích trình diễn, bạn tạo vòng lặp chương trình 10 lần bằng vòng lặp while.
Các
sau đó chương trình cố gắng truy cập tài nguyên quan trọng bằng cách tạo một tệp
khóa duy nhất, /tmp/LCK.test2. Nếu điều này
thất bại vì tập tin đã tồn tại, sau đó chương trình đợi trong một thời gian ngắn và thử
lại. Nếu nó thành công,
sau đó nó có thể truy cập vào tài nguyên và, trong phần được đánh dấu phần quan
trọng của Hồi giáo, anh ấy thực hiện bất kỳ việc xử lý nào
được yêu cầu với quyền truy cập độc quyền.


Vì đây chỉ là một cuộc biểu tình, bạn chỉ chờ trong một khoảng thời gian ngắn. Khi
chương trình kết thúc với
tài nguyên, nó giải phóng khóa bằng cách xóa tệp khóa. Sau đó nó có thể thực hiện
một số xử lý khác
(chỉ có chức năng ngủ trong trường hợp này) trước khi thử hỏi lại khóa. Tệp khóa hoạt
động như một nhị phân


semaphore, cung cấp cho mỗi chương trình một câu trả lời có hoặc không cho câu hỏi,
tôi có thể sử dụng tài nguyên không?
tìm hiểu thêm về semaphores trong Chương 14.
Điều quan trọng là phải nhận ra rằng đây là một sự sắp xếp hợp tác và bạn phải viết
các chương trình chính xác cho nó hoạt động. Một chương trình không thể tạo tập tin
khóa có thể chỉ cần xóa tập tin và thử lại. Sau đó nó có thể tạo tệp khóa, nhưng
chương trình khác tạo tệp khóa không có cách nào để biết rằng nó không còn có quyền
truy cập độc quyền vào tài nguyên
Locking Regions
Tạo tập tin khóa là tốt để kiểm soát truy cập độc quyền vào các tài nguyên như cổng
nối tiếp hoặc không thường xuyên
truy cập các tệp, nhưng nó rất tốt để truy cập vào các tệp được chia sẻ lớn. Giả sử bạn
có một tệp lớn được viết
bởi một chương trình nhưng được cập nhật bởi nhiều chương trình khác nhau cùng
một lúc. Điều này có thể xảy ra nếu một chương trình là
ghi nhật ký một số dữ liệu thu được liên tục trong một thời gian dài và đang được xử
lý bởi một số khác
các chương trình. Các chương trình xử lý có thể được chờ đợi để chương trình đăng
nhập kết thúc - nó chạy liên tục vì vậy họ cần một số cách hợp tác để cung cấp quyền truy cập đồng thời vào cùng một
tệp.
Bạn có thể giải quyết tình huống này bằng cách khóa các vùng của tệp sao cho một
phần cụ thể của tệp là
bị khóa, nhưng các chương trình khác có thể truy cập các phần khác của tệp. Đây
được gọi là phân đoạn tệp hoặc vùng tệp, khóa.
Linux có (ít nhất) hai cách để làm điều này: sử dụng lệnh gọi hệ thống fcntl và sử
dụng lệnh gọi lockf. Nhìn có vẻ tốt
chủ yếu ở giao diện fcntl vì đó là giao diện được sử dụng phổ biến nhất. lockf là hợp

tương tự, và trên Linux, thông thường chỉ là một giao diện thay thế cho fcntl. Tuy
nhiên, fcntl và lockf
các cơ chế khóa không hoạt động cùng nhau: Chúng sử dụng các triển khai cơ bản
khác nhau, vì vậy bạn nên
Không bao giờ trộn lẫn hai loại cuộc gọi; dính vào cái này hay cái khác
Bạn đã gặp cuộc gọi fcntl trong Chương 3. Định nghĩa của nó là


#include
int fcntl(int fildes, int command, ...);
fcntl hoạt động trên các mô tả tệp mở và, tùy thuộc vào tham số lệnh, có thể thực hiện
khác nhau nhiệm vụ. Ba tùy chọn lệnh quan tâm để khóa tệp như sau:
❑ F_GETLK
❑ F_SETLK
❑ F_SETLKW
Khi bạn sử dụng các đối số thứ ba này phải là một con trỏ tới một đàn struct, vì vậy
nguyên mẫu có hiệu quả như sau:
int fcntl(int fildes, int command, struct flock *flock_structure);
Cấu trúc flock (file lock) phụ thuộc vào việc triển khai, nhưng nó sẽ chứa ít nhất các
mục sau ,các thành viên:
❑ short l_type;
❑ short l_whence;
❑ off_t l_start;
❑ off_t l_len;
❑ pid_t l_pid;
Thành viên l_type lấy một trong một số giá trị, cũng được xác định trong fcntl.h.
Chúng được hiển thị trong bảng sau:

Các thành viên l_whence, l_start và l_len xác định một vùng - một tập hợp các byte
liền kề - trong một tệp .. l_whence phải là một trong những CatchK_SET,
SEEK_CUR, SEEK_END (từ unistd.h). Những cái này tương ứng với sự khởi đầu, vị
trí hiện tại và kết thúc của một tập tin, tương ứng. l_whence định nghĩa phần bù cho


l_start, byte đầu tiên trong khu vực, là tương đối. Thông thường, đây sẽ là
XEMK_SET, vì vậy l_start được tính từ đầu tập tin. Tham số l_len xác định số lượng
byte trong vùng. Tham số l_pid được sử dụng để báo cáo quá trình giữ khóa; xem mô
tả c
Mỗi byte trong một tệp chỉ có thể có một loại khóa duy nhất trên đó tại một thời điểm
và có thể bị khóa để chia sẻ truy cập, khóa để truy cập độc quyền, hoặc mở khóa. Có
khá nhiều tổ hợp lệnh và tùy chọn cho lệnh gọi fcntl, vì vậy hãy lần lượt xem xét từng
cái.ủa F_GETLK
The F_GETLK Command
Lệnh đầu tiên của anh ta là F_GETLK. Nó được khóa thông tin về tập tin fildes (tham
số đầu tiên) đã mở Nó không cố gắng khóa tập tin. Quá trình gọi chuyển thông tin về
loại khóa nó có thể muốn tạo và fcntl được sử dụng với lệnh F_GETLK trả về bất kỳ
thông tin nào có thể ngăn chặn khóa xảy ra. Các giá trị được sử dụng trong cấu trúc
đàn được mô tả trong bảng sau:

Một quy trình có thể sử dụng lệnh gọi F_GETLK để xác định trạng thái khóa hiện tại
trên một vùng của tệp. Nó nên thiết lập cấu trúc đàn để chỉ ra loại khóa mà nó có thể
yêu cầu và xác định vùng mà nó quan tâm trong. Cuộc gọi fcntl trả về giá trị khác -1
nếu nó thành công. Nếu tập tin đã có khóa ngăn chặn yêu cầu khóa thành công, nó ghi
đè lên cấu trúc đàn với các thông tin liên quan.
Nếu khóa sẽ thành công, cấu trúc đàn không thay đổi. Nếu cuộc gọi F_GETLK không
thể nhận được thông tin, nó trả về -1 để chỉ sự thất bại. Nếu cuộc gọi F_GETLK thành
công (nghĩa là, nó sẽ trả về một giá trị khác -1), ứng dụng gọi điện phải kiểm tra nội
dung của cấu trúc đàn để xác định xem nó đã được sửa đổi hay chưa. Vì giá trị l_pid
được đặt cho quá trình khóa (nếu tìm thấy), đây là trường thuận tiện để kiểm tra để
xác định xem cấu trúc đàn đã được thay đổi.
The F_SETLK Command
Lệnh này cố gắng khóa hoặc mở khóa một phần của tệp được tham chiếu bởi fildes.
Các giá trị được sử dụng trong
Cấu trúc flock (và khác với cấu trúc đàn được sử dụng bởi F_GETLK) như sau:


Như với F_GETLK, khu vực bị khóa được xác định bởi các giá trị của l_start,
l_whence và l_len các lĩnh vực của cấu trúc đàn. Nếu khóa thành công, fcntl trả về giá
trị khác -1; trên thất bại, -1 là trả lại. Hàm luôn trả về ngay lập tức.
The F_SETLKW Command
Lệnh F_SETLKW giống như lệnh F_SETLK ở trên, ngoại trừ việc nếu nó có thể có
được thì khóa, cuộc gọi sẽ đợi cho đến khi nó có thể. Khi cuộc gọi này đã bắt đầu chờ,
nó sẽ chỉ trở lại khi khóa có thể thu được hoặc một tín hiệu xảy ra. Chúng tôi bao gồm
các tín hiệu trong Chương 11. Tất cả các khóa được giữ bởi một chương trình trên một
tệp sẽ tự động bị xóa khi mô tả tệp có liên quan được đóng lại. Điều này cũng tự động
xảy ra khi chương trình kết thúc.
Use of read and write with Locking
Khi bạn sử dụng tính năng khóa trên các vùng của tệp, điều đó rất quan trọng để sử
dụng chức năng đọc cấp thấp hơn và viết các cuộc gọi để truy cập dữ liệu trong tệp,
chứ không phải là fread và fwrite cấp cao hơn. Điều này là cần thiết bởi vì fread và
fwrite thực hiện việc đệm dữ liệu đọc hoặc ghi bên trong thư viện, do đó, thực hiện
một cuộc gọi fread để đọc 100 byte đầu tiên của một tệp có thể (thực tế gần như chắc
chắn sẽ) đọc nhiều hơn 100 byte và đệm dữ liệu bổ sung bên trong thư viện. Nếu
chương trình sử dụng fread để đọc 100 byte tiếp theo, nó thực sự sẽ đọc dữ liệu đã
được lưu trong thư viện và không cho phép mức thấp đọc để kéo thêm dữ liệu từ tập
tin Để xem tại sao đây là một vấn đề, hãy xem xét hai chương trình muốn cập nhật
cùng một tệp. Giả sử tập tin bao gồm 200 byte dữ liệu, tất cả các số không. Chương
trình đầu tiên bắt đầu trước và có được khóa ghi trên 100 đầu tiên byte của tập tin. Sau
đó, nó sử dụng fread để đọc trong 100 byte đó. Tuy nhiên, như thể hiện trong một
chương trước, Fread sẽ đọc trước tối đa các byte BUFSIZ, vì vậy nó thực sự đọc toàn
bộ tệp vào bộ nhớ, nhưng chỉ chuyển 100 byte đầu tiên trở lại chương trình. Chương
trình thứ hai sau đó bắt đầu. Nó nhận được một khóa ghi trên 100 byte thứ hai của
chương trình. Đây là thành công vì chương trình đầu tiên chỉ khóa 100 byte đầu tiên.
Chương trình thứ hai viết twos để byte 100 đến 199, đóng tệp, mở khóa và thoát.
Chương trình đầu tiên sau đó khóa 100 byte thứ hai của tệp và gọi fread để đọc chúng.
Vì dữ liệu đó đã được thư viện đệm vào bộ nhớ, những gì chương trình thực sự nhìn
thấy là 100 byte số không, không phải là 100 twos thực sự tồn tại trong tệp trên ổ đĩa


cứng. Vấn đề này không xảy ra khi bạn sử dụng đọc và viết. Mô tả về việc khóa tập
tin có vẻ hơi phức tạp, nhưng nó thực sự khó mô tả hơn nó là để sử dụng.


Làm thế nào nó hoạt động
Chương trình trước tiên tạo một tệp, mở nó cho cả đọc và viết, sau đó điền vào tệp
với dữ liệu. Sau đó, nó thiết lập hai vùng: vùng đầu tiên từ byte 10 đến 30, cho khóa
được chia sẻ (đọc) và vùng thứ hai từ byte 40 đến 50, cho một khóa (ghi) độc quyền.
Sau đó, nó gọi fcntl để khóa hai vùng và chờ một vài phút trước khi đóng tệp và thoát.
Hình 7-1 hiển thị kịch bản này với các khóa khi chương trình bắt đầu chờ.

Về bản thân, chương trình này không phải là rất hữu ích. Bạn cần một chương trình
thứ hai để kiểm tra các khóa, lock4.c.



Để kiểm tra khóa, trước tiên bạn cần chạy chương trình lock3; sau đó chạy chương
trình lock4 để kiểm tra khóa tập tin. Bạn làm điều này bằng cách thực hiện chương
trình lock3 trong nền, với lệnh sau:
$ ./lock3 &
$ process 1534 locking file
Dấu nhắc lệnh trả về vì lock3 đang chạy trong nền và sau đó bạn ngay lập tức chạy
chương trình lock4 bằng lệnh sau:
$ ./lock4
Đầu ra bạn nhận được, với một số thiếu sót cho ngắn gọn, như sau:
Testing F_WRLOCK on region from 0 to 5
F_WRLCK - Lock would succeed
Testing F_RDLOCK on region from 0 to 5
F_RDLCK - Lock would succeed


...
Testing F_WRLOCK on region from 10 to 15
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 1534
Testing F_RDLOCK on region from 10 to 15
F_RDLCK - Lock would succeed
Testing F_WRLOCK on region from 15 to 20
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 1534
Testing F_RDLOCK on region from 15 to 20
F_RDLCK - Lock would succeed
...
Testing F_WRLOCK on region from 25 to 30
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 1534
Testing F_RDLOCK on region from 25 to 30
F_RDLCK - Lock would succeed
...
Testing F_WRLOCK on region from 40 to 45
Lock would fail. F_GETLK returned:
l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 1534
Testing F_RDLOCK on region from 40 to 45
Lock would fail. F_GETLK returned:
l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 1534
...
Testing F_RDLOCK on region from 95 to 100
F_RDLCK - Lock would succeed

Làm thế nào nó hoạt động Đối với mỗi nhóm năm byte trong tệp, lock4 thiết lập cấu
trúc vùng để kiểm tra các khóa trên tệp, mà nó sau đó sử dụng để xác định xem vùng
có thể bị ghi hoặc đọc bị khóa hay không. Các thông tin trả về hiển thị các byte vùng,
offset từ byte 0, điều đó sẽ khiến yêu cầu khóa không thành công. Vì phần l_pid của
cấu trúc được trả về chứa định danh quy trình của chương trình hiện có tệp bị khóa,
chương trình đặt nó thành -1 (một giá trị không hợp lệ) và sau đó kiểm tra xem nó đã
được thay đổi khi fcntl trả lại cuộc gọi. Nếu khu vực hiện tại bị khóa, l_pid sẽ không
thay đổi. Để hiểu đầu ra, bạn cần xem tệp bao gồm fcntl.h (thường / usr / include /
fcntl.h) để thấy rằng một l_type của 1 là từ định nghĩa của F_WRLCK là 1 và một
l_type của 0 là từ định nghĩa của F_RDLCK là 0. Do đó, l_type của 1 cho bạn biết
rằng khóa sẽ không thành công do khóa ghi hiện có và l_type bằng 0 là do khóa đọc
hiện có. Trên các vùng của tập tin đó lock3 chưa bị khóa, cả khóa chia sẻ và khóa độc
quyền sẽ thành công. Từ byte 10 đến 30, bạn có thể thấy rằng có thể có khóa chia sẻ,


vì khóa hiện có từ chương trình lock3 là chia sẻ, không phải là khóa độc quyền. Trên
vùng từ byte 40 đến 50, cả hai loại khóa sẽ thất bại vì lock3 có khóa độc quyền
(F_WRLCK) trên khu vực này. Khi chương trình lock4 đã hoàn thành, bạn cần đợi
một khoảng thời gian ngắn để lock3 hoàn thành ngủ gọi và thoát.
Competing Locks
Bây giờ bạn đã thấy cách kiểm tra các khóa hiện có trên một tệp, hãy để Lừa xem điều
gì xảy ra khi hai chương trình cạnh tranh cho các khóa trên cùng một phần của tập tin.
Bạn sẽ sử dụng lại chương trình lock3 để khóa tập tin, và một chương trình mới,
lock5, để thử khóa lại. Để hoàn thành ví dụ, bạn cũng sẽ thêm một số cuộc gọi cho mở
khóa vào lock5
Tại đây, một chương trình, lock5.c, cố gắng khóa các vùng của tệp đã bị khóa, thay vì
kiểm tra trạng thái khóa của các phần khác nhau của tệp:

2. The remainder of the program specifies different regions of the file and tries
different locking operations on them:



Nếu bạn lần đầu chạy chương trình lock3 trong nền, thì ngay lập tức chạy chương
trình mới này:
$ ./lock3 &
$ process 227 locking file
$ ./lock5
Đầu ra bạn nhận được như sau:
Process 227 locking file
Process 228, trying F_RDLCK, region 10 to 15
Process 228 - obtained lock on region
Process 228, trying F_UNLCK, region 10 to 15
Process 228 - unlocked region
Process 228, trying F_UNLCK, region 0 to 50
Process 228 - unlocked region
Process 228, trying F_WRLCK, region 16 to 21
Process 228 - failed to lock on region
Process 228, trying F_RDLCK, region 40 to 50
Process 228 - failed to lock on region
Process 228, trying F_WRLCK with wait, region 16 to 21
Process 227 closing file
Process 228 - obtained lock on region
Process 228 ending
Làm thế nào nó hoạt động Đầu tiên, chương trình cố gắng khóa một vùng từ byte 10
đến 15 bằng khóa chung. Vùng này đã bị khóa bằng khóa chung, nhưng khóa chia sẻ
đồng thời được cho phép và khóa thành công. Sau đó, nó mở khóa chung của mình
trên khu vực, cũng thành công. Chương trình sau đó cố gắng để mở khóa 50 byte đầu


tiên của tập tin, mặc dù nó không có bất kỳ khóa nào được đặt. Điều này cũng thành
công bởi vì, mặc dù chương trình này không có khóa ở vị trí đầu tiên, kết quả cuối
cùng của yêu cầu mở khóa là không có khóa được tổ chức bởi chương trình này trong
50 byte đầu tiên. Tiếp theo, chương trình cố gắng khóa vùng từ byte 16 đến 21 bằng
một khóa độc quyền. Vùng này là cũng đã bị khóa với khóa dùng chung, vì vậy lần
này khóa mới không thành công, vì khóa độc quyền có thể không được tạo ra
Other Lock Commands
Có một phương pháp khóa tập tin thứ hai: chức năng lockf. Điều này cũng hoạt động
bằng cách sử dụng mô tả tập tin.
Nó có nguyên mẫu
#include
int lockf(int fildes, int function, off_t size_to_lock);
Nó có thể lấy các giá trị hàm sau:
❑ F_ULOCK: Unlock
❑ F_LOCK: Lock exclusively
❑ F_TLOCK: Test and lock exclusively
❑ F_TEST: Test for locks by other processes
Tham số size_to_lock là số byte để hoạt động, từ phần bù hiện tại trong tệp. lockf có
giao diện đơn giản hơn giao diện fcntl, chủ yếu vì nó có ít chức năng hơn và linh hoạt.
Để sử dụng chức năng, bạn phải tìm kiếm bắt đầu khu vực bạn muốn khóa và sau đó
gọi nó với số lượng byte để khóa. Giống như phương pháp khóa tập tin fcntl, tất cả
các khóa chỉ mang tính chất tư vấn; họ đã giành chiến thắng trong việc ngăn chặn việc
đọc từ hoặc viết vào tập tin. Nó có trách nhiệm của các chương trình để kiểm tra ổ
khóa. Tác dụng của việc trộn khóa fcntl và khóa lockf không được xác định, vì vậy
bạn phải quyết định loại khóa nào bạn muốn sử dụng và dính vào nó.
Deadlocks
Không có cuộc thảo luận nào về việc khóa sẽ được hoàn thành mà không đề cập đến
sự nguy hiểm của những bế tắc. Giả sử hai chương trình muốn cập nhật cùng một tập
tin. Cả hai cần cập nhật byte 1 và byte 2 cùng một lúc. Chương trình A chọn cập nhật
byte 2 trước, sau đó là byte 1. Chương trình B cố gắng cập nhật byte 1 trước, sau đó là
byte 2. Cả hai chương trình bắt đầu cùng một lúc. Chương trình A khóa byte 2 và
chương trình B khóa byte 1. Chương trình A cố gắng khóa trên byte 1. Vì chương
trình này đã bị khóa bởi chương trình B, chương trình A chờ. Chương trình B cố gắng
cho một khóa trên byte 2. Vì điều này bị khóa bởi chương trình A, chương trình B
cũng chờ.


Tình huống này, khi không chương trình nào có thể tiến hành, được gọi là bế tắc, hoặc
ôm hôn chết người. Đây là một vấn đề phổ biến với các ứng dụng cơ sở dữ liệu trong
đó nhiều người dùng thường cố gắng truy cập cùng dữ liệu. Hầu hết các cơ sở dữ liệu
quan hệ thương mại phát hiện các bế tắc và tự động phá vỡ chúng; Linux kernel
khôngn. Một số can thiệp từ bên ngoài, có lẽ buộc phải chấm dứt một trong các
chương trình, là bắt buộc để sắp xếp các mớ hỗn độn. Các lập trình viên phải cảnh
giác với tình huống này. Khi bạn có nhiều chương trình đang chờ khóa, bạn cần phải
rất cẩn thận để xem xét liệu một bế tắc có thể xảy ra. Trong ví dụ này, nó khá dễ tránh:
Cả hai chương trình chỉ cần khóa các byte mà chúng yêu cầu theo cùng một thứ tự
hoặc sử dụng vùng lớn hơn để khóa. Chúng tôi không có không gian để xem xét
những khó khăn của các chương trình đồng thời ở đây. Nếu bạn có hứng thú đọc thêm,
bạn có thể cân nhắc việc có được một bản sao Nguyên tắc đồng thời và phân tán
Lập trình bởi M. Ben-Ari (Prentice Hall, 1990).



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay

×

×