2009-09-28 37 views
42

Một số triển khai có tốt hơn các ứng dụng khác cho các ứng dụng cụ thể không? Có bất cứ điều gì để kiếm được bằng cách tung ra của riêng bạn?Các mutex được triển khai như thế nào?

+7

"Có bất kỳ điều gì để kiếm được bằng cách tự mình thực hiện không?" Hiểu biết? –

+14

"Có điều gì để kiếm tiền bằng cách tự mình thực hiện không?" - vâng, mã thiếu sót! ;) –

+5

@Mitch Wheat - Chắc chắn, người ta không nên sử dụng thư viện muteb homebrew cho mã sản xuất, nhưng rất nhiều người thích học bằng cách làm và viết [application x] của bạn rất thông tin. –

Trả lời

21

Xem mô tả về hướng dẫn máy Test-and-set trên Wikipedia, điều này ám chỉ đến cách hoạt động nguyên tử đạt được ở cấp máy. Tôi có thể tưởng tượng hầu hết các triển khai mutex cấp độ ngôn ngữ dựa trên sự hỗ trợ mức máy như Test-and-set.

+0

Ví dụ, trên x86, bạn có thể sử dụng lệnh 'xchg' để hoán đổi nguyên tử một thanh ghi với bộ nhớ. Phần cửa hàng là "bộ", và phần nhánh + tải trên giá trị đăng ký là phần "kiểm tra" một nửa của phép toán thử và thiết lập. Và vâng, đây là nhiều hơn hoặc ít hơn những gì bạn làm trong thực tế. Xem [thực hiện spinlock tối thiểu này trong asm] (https://stackoverflow.com/questions/37241553/locks-around-memory-manipulation-via-inline-assembly/37246263#37246263) mà hầu hết các công cụ quan trọng ngoại trừ rơi trở lại ngủ trong một cuộc gọi hệ thống sau khi quay một lúc mà không cần khóa. –

2

Interlocked.CompareExchange là đủ để triển khai khóa xoay vòng. Nó khá khó khăn để làm ngay mặc dù. Xem cho Joe Duffy's blog để biết ví dụ về sự tinh tế có liên quan.

+0

Chúng tôi đang nói về các giải pháp bất khả tri về ngôn ngữ ở đây, nhưng cảm ơn nỗ lực của bạn. –

+0

Ồ, bạn nói đúng. Tôi không biết tại sao tôi lại nghĩ .NET. Có lẽ vì những câu trả lời khác. – Joren

6

A mutex tốt nhất nên chạy trong hạt nhân của hệ điều hành trong khi vẫn giữ số lượng mã xung quanh càng ngắn càng tốt, để tránh bị cắt trong khi chuyển sang tác vụ khác. Do đó, việc thực hiện chính xác là một bí mật. Nó không phức tạp. Về cơ bản nó là một đối tượng có một trường boolean, nó nhận và đặt.

  • Khi sử dụng bộ đếm, nó có thể trở thành Semaphore.
  • Một mutex là điểm bắt đầu cho một phần quan trọng, sử dụng một mutex nội bộ để xem liệu nó có thể nhập một phần mã hay không. Nếu các mutex là miễn phí, nó đặt mutex và thực thi mã, chỉ để phát hành mutex khi thực hiện. Khi một phần quan trọng thông báo rằng một mutex bị khóa, nó có thể chờ đợi cho mutex được phát hành.

Xung quanh logic mutex cơ bản có trình bao bọc để bọc nó trong một đối tượng .. Sau đó, thêm các đối tượng bao bọc để làm cho nó có sẵn bên ngoài hạt nhân. Và sau đó một wrapper để làm cho nó có sẵn trong. Và sau đó một số lập trình viên sẽ viết mã wrapper riêng của họ xung quanh tất cả cho nhu cầu hợp lý của riêng họ. Trình bao bọc xung quanh trình bao bọc thực sự khiến chúng trở thành một lãnh thổ u ám.

Bây giờ, với kiến ​​thức cơ bản này về nội bộ của các mutex, tất cả những gì tôi hy vọng là bạn sẽ sử dụng một triển khai dựa trên hạt nhân và phần cứng bên dưới. Đây sẽ là đáng tin cậy nhất. Nếu phần cứng mà bạn đang sử dụng không hoạt động ở cấp độ hạt nhân/phần cứng này thì nó vẫn có thể đáng tin cậy nhưng tôi khuyên bạn không nên sử dụng nó, trừ khi không có sự thay thế nào khác.

Theo như tôi biết, Windows, Linux và .NET tất cả sẽ sử dụng mutexes ở cấp hạt nhân/phần cứng.

Trang Wikipedia mà tôi đã liên kết để giải thích thêm về logic nội bộ và các triển khai có thể có. Tốt hơn là, một mutex được điều khiển bởi phần cứng, do đó làm cho toàn bộ việc nhận/thiết lập của mutex là indivisible step. (Chỉ để đảm bảo hệ thống không chuyển đổi tác vụ ở giữa.)

+0

+1. Câu trả lời hay. –

+0

Ý bạn là bí mật? Không phải toàn bộ mã nguồn hạt nhân Linux có sẵn trong GitHub không? –

+0

Ồ, geez. Đó là 8 năm trước khi tôi viết điều đó! :) Nhưng yeah, nó là một bí mật vì không ai thực sự kiểm tra mã nguồn cho mutexes trong hạt nhân Linux. Và những người kiểm tra nó thường sẽ tìm ra giải mã logic đằng sau nó khó khăn. Xem https://github.com/torvalds/linux/blob/master/kernel/locking/mutex.c cho mã Mutex trong Linux ... May mắn thay, nó cũng được nhận xét. Tuy nhiên, phức tạp. Như tôi đã nói, * một chút * bí mật ... –

-1

Tôi đã sử dụng Reflector.NET để dịch ngược nguồn cho System.Threading.ReaderWriterLockSlim, được thêm vào phiên bản .NET framework gần đây.

Chủ yếu sử dụng Interlocked.CompareExchange, Thread.SpinWaitThread.Sleep để đạt được đồng bộ hóa. Có một vài trường hợp EventWaitHandle (đối tượng hạt nhân) được sử dụng trong một số trường hợp.

Ngoài ra còn có một số phức tạp được thêm vào để hỗ trợ reentrancy trên một chủ đề duy nhất.

Nếu bạn quan tâm đến lĩnh vực này và làm việc trong .NET (hoặc ít nhất, có thể đọc nó) thì bạn có thể thấy khá thú vị khi kiểm tra lớp học này.

18

Xây dựng trên đề xuất của test-and-set của Adamski, bạn cũng nên xem khái niệm "mutexes không gian người dùng nhanh" hoặc futexes.

Futexes có thuộc tính mong muốn rằng chúng không yêu cầu gọi hệ thống hạt nhân trong các trường hợp phổ biến là khóa hoặc mở khóa một đột biến uncontended. Trong những trường hợp này, mã chế độ người dùng sử dụng thành công hoạt động compare and swap (CAS) nguyên tử để khóa hoặc mở khóa mutex.

Nếu CAS không thành công, mutex được đấu và gọi hệ thống hạt nhân - sys_futex trong Linux - phải được sử dụng để chờ mutex (trong trường hợp khóa) hoặc đánh thức các chủ đề khác (trong trường hợp mở khóa) .

Nếu bạn nghiêm túc về việc tự mình triển khai, hãy đảm bảo bạn cũng đọc số paper của Ulrich Drepper.

Các vấn đề liên quan