Tại sao hầu hết các triển khai mutex không công bằng?


11

Tôi hiểu rằng hầu hết các triển khai phổ biến của một mutex (ví dụ std :: mutex trong C ++) không đảm bảo tính công bằng - nghĩa là, họ không đảm bảo rằng trong các trường hợp tranh chấp, khóa sẽ được lấy bởi các luồng theo thứ tự mà họ gọi là khóa (). Trên thực tế, thậm chí có thể (mặc dù hy vọng là không phổ biến) rằng trong trường hợp có sự tranh chấp cao, một số chủ đề đang chờ để có được mutex có thể không bao giờ có được nó.

Điều này có vẻ như là một hành vi không có ích với tôi - dường như với tôi rằng một mutex công bằng sẽ mang lại hành vi phù hợp hơn với những gì một lập trình viên muốn / mong đợi.

Lý do được đưa ra là tại sao các mutex thường không được triển khai để công bằng là "hiệu suất", nhưng tôi muốn hiểu rõ hơn điều đó có nghĩa là gì - đặc biệt, làm thế nào để thư giãn yêu cầu công bằng của mutex cải thiện hiệu suất? Có vẻ như một mutex "công bằng" sẽ không quan trọng để thực hiện - chỉ cần khóa () nối chuỗi cuộc gọi vào đuôi của danh sách được liên kết của mutex trước khi đưa luồng vào chế độ ngủ, sau đó mở khóa () bật chuỗi tiếp theo từ người đứng đầu danh sách đó và đánh thức nó

Cái nhìn sâu sắc về triển khai mutex nào tôi còn thiếu ở đây, điều đó sẽ giải thích tại sao nó được coi là đáng giá để hy sinh sự công bằng để có hiệu suất tốt hơn?


1
Danh sách được liên kết đó cho mọi mutex sẽ phải là một cấu trúc dữ liệu được chia sẻ, phải không? Vì vậy, làm thế nào bạn sẽ ngăn chặn các cuộc đua dữ liệu trên đó mà không làm giảm hiệu suất?
dùng3543290

Sử dụng một cơ chế danh sách liên kết không khóa, tôi nghĩ vậy. Cấu trúc dữ liệu nào sử dụng mutex không công bằng, để tìm chuỗi tiếp theo đánh thức?
Jeremy Friesner

1
Bạn sẽ phải tìm kiếm điều đó, nhưng một danh sách liên kết không khóa có đảm bảo sự công bằng không? Tôi nghĩ rằng bạn sẽ thấy rằng sự đảm bảo như sự công bằng trong lập trình đồng thời là khó thực hiện.
dùng3543290

Câu trả lời:


7

Câu trả lời của Jim Sawy chỉ ra một câu trả lời: Khi bạn có chủ đề với các ưu tiên khác nhau, hành vi "công bằng" sẽ không chính xác. Khi bạn có nhiều luồng có thể chạy, luồng ưu tiên cao nhất thường là luồng nên chạy.

Tuy nhiên, có một bí mật ít được thảo luận về việc triển khai hệ điều hành mà bạn nên biết, đó là đôi khi các hệ điều hành chạy mã với tư cách là người dùng bằng cách chiếm quyền điều khiển của người dùng. Vì lý do an toàn, hầu hết các hệ điều hành làm điều này chỉ làm điều đó trong khi một luồng bị chặn. Khi hệ điều hành hoàn tất, luồng được treo lại và điều này thường có tác dụng di chuyển luồng đến phía sau hàng đợi.

Một ví dụ điển hình là trình xử lý tín hiệu trong Unix, bẫy hệ thống không đồng bộ trong VMS hoặc cuộc gọi thủ tục không đồng bộ trong Windows NT. Về cơ bản tất cả đều giống nhau: Hệ điều hành cần thông báo cho quá trình người dùng rằng một số sự kiện đã xảy ra và điều này được xử lý bằng cách chạy mã trong không gian người dùng.

Nhiều dịch vụ hệ điều hành như I / O không đồng bộ thường được triển khai trên cơ sở này.

Một ví dụ khác là nếu quá trình này nằm dưới sự kiểm soát của trình gỡ lỗi. Trong trường hợp đó, hệ thống gỡ lỗi có thể thực thi mã dưới dạng tác vụ người dùng vì nhiều lý do.


4

"Đảo ngược ưu tiên" là một lý do mà sự công bằng có thể là không mong muốn. Một quá trình ưu tiên thấp đánh vào mutex bị khóa và ngủ. Sau đó, một quá trình ưu tiên cao hơn đánh nó, và cũng ngủ. Khi mutex mở khóa, quá trình nào sẽ có được khóa tiếp theo?


Chào mừng bạn đến với trang web và cảm ơn vì đã trả lời một câu hỏi đang ngồi một lúc mà không có câu trả lời! Câu trả lời của bạn là, tất nhiên là đúng, nhưng tôi cảm thấy nó có thể có một chút chi tiết hơn.
David Richerby

3

Một mutex công bằng sẽ dành nhiều thời gian bị khóa hơn là một mutex không công bằng, tất cả những thứ khác đều bình đẳng. Bởi vì một chủ đề phát hành một mutex không công bằng luôn có thể chỉ cần mở khóa nó. Nhưng một chủ đề phát hành một mutex công bằng chỉ có thể mở khóa nó khi hàng đợi bồi bàn trống. Mặt khác, luồng phát hành phải để khóa mutex vì mục đích của luồng tiếp theo, còn gọi là luồng đầu tiên trên hàng đợi người phục vụ, sau đó bị mất hiệu lực và bị đánh thức. Mutex vẫn bị khóa ít nhất cho đến khi luồng mới được lên lịch trên CPU, có thể là một thời gian dài nếu có nhiều luồng hiện có thể chạy được.

Và nếu luồng phát hành kịp thời cố gắng lấy lại cùng một mutex, nó phải đặt chính nó vào phía sau hàng đợi của người phục vụ và đi ngủ. Điều này sẽ không xảy ra nếu luồng không phát hành mutex để bắt đầu. Do đó, điều này khuyến khích các phần quan trọng "tham lam" lâu hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.