2011-10-23 25 views
6

thể trùng lặp:
Why can't you sleep while holding spinlock?Tại sao "ngủ" không được phép khi cầm một ổ khóa?

Theo như tôi biết, spinlocks nên được sử dụng trong thời gian ngắn, và chỉ lựa chọn trong mã như xử lý ngắt nơi ngủ (quyền ưu tiên) là không cho phép.

Tuy nhiên, tôi không biết tại sao có "quy tắc" như vậy mà KHÔNG NÊN ngủ hoàn toàn trong khi cầm một ổ khóa. Tôi biết rằng nó không phải là một thực hành được đề nghị (vì nó là bất lợi trong hoạt động), nhưng tôi thấy không có lý do tại sao giấc ngủ KHÔNG được phép trong spinlocks.

Bạn không thể giữ khóa quay trong khi bạn có được semaphore, vì bạn có thể phải ngủ trong khi chờ semaphore, và bạn không thể ngủ trong khi giữ khóa quay (từ "Linux Kernel Development" của Robert Love) .

Lý do duy nhất tôi có thể thấy là vì lý do di chuyển, bởi vì trong bộ xử lý, spinlocks được thực hiện như vô hiệu hóa ngắt và tắt ngắt, ngủ sẽ không được phép (nhưng ngủ sẽ không phá vỡ mã trong hệ thống SMP) .

Nhưng tôi tự hỏi nếu lý do của tôi là chính xác hoặc nếu có bất kỳ lý do nào khác.

+1

Quy tắc này bạn nói đến là gì? –

+0

Tôi chỉ cần thêm một trích dẫn khối từ một cuốn sách mà qustion của tôi phát sinh. – SHH

+0

Điều đó trông giống như một cái gì đó đặc trưng cho sự phát triển hạt nhân Linux. Nếu bạn đang nói về phát triển hạt nhân Linux thì vui lòng gắn thẻ câu hỏi cho phù hợp. –

Trả lời

13

Có nhiều lý do tại sao, ít nhất là trong Linux, ngủ trong spinlocks không được phép:

  1. Nếu thread ngủ trong một spinlock, và thread B sau đó cố gắng để có được các spinlock cùng, một hệ thống uniprocessor sẽ bế tắc. Chủ đề B sẽ không bao giờ đi ngủ (bởi vì spinlocks không có danh sách chờ cần thiết để đánh thức B khi A được thực hiện), và thread A sẽ không bao giờ có cơ hội để thức dậy.
  2. Vòng xoay được sử dụng trên các hình thù chính xác vì chúng hiệu quả hơn - cung cấp bạn không tranh cãi lâu. Cho phép ngủ có nghĩa là bạn sẽ có thời gian tranh chấp lâu dài, xóa tất cả lợi ích của việc sử dụng spinlock. Hệ thống của bạn sẽ nhanh hơn chỉ bằng cách sử dụng semaphore trong trường hợp này.
  3. Vòng xoay thường được sử dụng để đồng bộ hóa với trình xử lý ngắt, bằng cách bổ sung tắt ngắt. Trường hợp sử dụng này là không thể nếu bạn ngủ (một khi bạn nhập trình xử lý ngắt, bạn không thể chuyển về chủ đề để cho nó thức dậy và kết thúc phần quan trọng của spinlock).

Sử dụng đúng công cụ cho đúng công việc - nếu bạn cần ngủ, ẩn dụ và mutexes là bạn của bạn.

+1

Thực tế các semaphores thực sự không nên được sử dụng trong mã hạt nhân trừ khi bạn có một trường hợp sử dụng rất chuyên dụng (thực sự nếu bạn đang đọc câu hỏi này trên stackoverflow, bạn không cần semaphores :) Chỉ cần sử dụng mutexes để khóa khi bạn cần ngủ, và spinlocks khi bạn cần khóa trong một bối cảnh không thể ngủ được. – Roland

+0

@bdonlan Tôi có nghi ngờ về điểm 1. Bạn đã nói rằng luồng A sẽ không bao giờ thức dậy? Tại sao vậy? Khi lát thời gian cho chủ đề B sẽ kết thúc và thời gian ngủ cho luồng sẽ kết thúc, luồng A sẽ thực thi bằng cách sử dụng lát thời gian của nó và sau khi thực hiện xong sẽ giải phóng khóa. Nó không phải là trường hợp? –

+2

@SumitTrehan: Tốt. Nếu spinlock không phải là thứ cần thiết cho bản thân lịch trình, và luồng B không ở trong bối cảnh ngắt và không bị ngắt hoặc vô hiệu hóa, thì cuối cùng luồng B có thể được đặt trước. Tuy nhiên, trong linux, việc ưu tiên luôn bị vô hiệu hóa khi một spinlock được giữ (hoặc sắp được giữ). Điều này là do nếu một thread đang giữ một spinlock trong khi không chạy, các luồng khác lãng phí rất nhiều thời gian quay trên khóa, và có khả năng bế tắc với các trình xử lý ngắt. Vì vậy, trong thực tế thread B sẽ không được preemptible và sẽ bế tắc. – bdonlan

7
  • Trên thực tế, bạn có thể ngủ với ngắt bị vô hiệu hóa hoặc một số loại khác loại trừ hoạt động. Nếu không, điều kiện mà bạn đang ngủ có thể thay đổi trạng thái do gián đoạn và sau đó bạn sẽ không bao giờ thức dậy. Mã ngủ sẽ không bao giờ được nhập nếu không có mức độ ưu tiên cao hoặc một số phần quan trọng khác bao quanh đường dẫn thực hiện giữa quyết định ngủ và chuyển ngữ cảnh.

  • Nhưng đối với khóa xoay, ngủ là một thảm họa, khi khóa vẫn được đặt.Chủ đề khác sẽ quay khi họ đánh nó, và họ sẽ không ngừng quay cho đến khi bạn thức dậy từ giấc ngủ. Đó có thể là vĩnh cửu so với số ít spin được mong đợi trong trường hợp xấu nhất tại một spinlock, bởi vì spinlocks tồn tại chỉ để đồng bộ hóa quyền truy cập vào các vị trí bộ nhớ, chúng không phải tương tác với cơ chế chuyển đổi ngữ cảnh.

    (Cho rằng vấn đề, mỗi chủ đề khác có thể cuối cùng nhấn spinlock và sau đó bạn sẽ rúc mỗi chủ đề của mỗi cốt lõi của toàn bộ hệ thống.)

+0

Bạn có thể xây dựng điểm đầu tiên không? – SHH

+0

Điểm đầu tiên là sai. Bạn không thể ngủ với các ngắt bị vô hiệu hóa; để đối phó với các chủng tộc ám chỉ đến đó, chỉ cần làm mọi thứ theo thứ tự đúng: đặt trạng thái của bạn thành TASK_INTERRUPTIBLE, kiểm tra điều kiện và sau đó là 'schedule()' - hoặc chỉ sử dụng 'wait_event()', xử lý điều này cho bạn . – Roland

+0

@Roland, tôi chỉ đề cập đến quan điểm của mã quá trình hạt nhân, vì vậy bạn _can, _ theo nghĩa gọi một điểm vào 'schedule()' hoặc 'sleep()'. Cơ chế ngủ của nhân sẽ kích hoạt lại các ngắt. Tất cả các hạt nhân phổ biến là SMP bây giờ nên việc vô hiệu hóa ngắt không thực hiện được nhiều hơn nữa, nhưng chắc chắn, nó sẽ không thực hiện bất kỳ lệnh _wait-for-interrupt_ phần cứng nào mà không cần phải bật lại các ngắt. – DigitalRoss

1

Bạn có thể không phải khi bạn sử dụng một khóa spin vì nó là có nghĩa là để được sử dụng. Khóa xoay được sử dụng ở những nơi thực sự cần thiết để bảo vệ các vùng quan trọng và cấu trúc dữ liệu được chia sẻ. Nếu bạn có được một trong khi cũng giữ một semaphore, bạn khóa truy cập đến bất kỳ khu vực quan trọng (nói) khóa của bạn được gắn vào (nó thường là một thành viên của một cấu trúc dữ liệu lớn hơn cụ thể), trong khi cho phép quá trình này có thể được đưa vào giấc ngủ. Nếu, nói, một IRQ được nâng lên trong khi quá trình này ngủ, và xử lý IRQ cần truy cập vào khu vực quan trọng vẫn bị khóa, nó bị chặn, mà không bao giờ có thể xảy ra với IRQ. Rõ ràng, bạn có thể tạo ra các ví dụ mà khóa spin của bạn không được sử dụng theo cách nó nên (một khóa spin giả định gắn liền với một vòng nop, nói); nhưng đó không phải là một khóa quay thực sự được tìm thấy trong nhân Linux.