Điều này phụ thuộc vào cách khóa được thực hiện. Nếu bạn làm điều đó như trong bài viết Wikipedia, tức là bảo vệ phần quan trọng với một boolean cho mỗi quy trình¹, bạn chắc chắn sẽ gặp rắc rối. Nếu một tiến trình chết, nó không bao giờ đặt lại cờ của nó để quá trình kia lặp lại mãi mãi.
Trong thực tế, bạn có thể bảo vệ mã của mình trước nhiều cách chết. Ví dụ: hãy thực hiện kiểu Java này:
flag[1] = true;
turn = 1;
while ( flag[0] == true && turn == 1 ) { Thread.yield(); }
try {
// critical section
}
finally {
flag[1] = false;
}
Điều này sẽ đảm bảo cờ được đặt lại bất cứ điều gì xảy ra trong phần quan trọng, miễn là hệ thống đang xử lý lỗi. Trong Java, điều đó đúng ngay cả đối với stack và heap tràn. Vì vậy, trừ khi quá trình biến mất theo nghĩa đen ( kill
², lỗi bộ xử lý, ngắt kết nối mạng, ...) bạn vẫn an toàn. Lưu ý rằng hầu hết các phần mềm không quan trọng đều bị lỗi trong những trường hợp này - làm thế nào nó có thể xử lý một lỗi mà nó không chạy? - vì vậy mà phải được chấp nhận trong nhiều trường hợp. Bạn có thể xử lý sự không nhất quán khi khởi động lại nếu cần thiết.
Nếu bạn sử dụng các khóa cấp độ ngôn ngữ phù hợp, hệ thống thời gian chạy có thể xử lý các chủ sở hữu khóa biến mất, tức là giải phóng các khóa với chủ sở hữu đã chết. Bạn có thể tự mô phỏng điều này bằng cách cung cấp cho mỗi quy trình một công tắc của người chết mà những người khác có thể đọc hoặc kiểm tra trực tiếp xem quy trình sở hữu khóa có còn tồn tại không (nếu hệ thống hỗ trợ nó).
- Điều đó không quy mô tốt, dù sao.
- Trong Java, tôi nghĩ
finalize
nên thực hiện ngay cả trên kill
, nhưng điều này không được đảm bảo bởi thông số kỹ thuật. kill -9
có lẽ là một bản án tử hình cho bất kỳ giải pháp nào đòi hỏi quá trình chết để làm một cái gì đó.