1. Trang chủ
  2. » Công Nghệ Thông Tin

Vấn đề đồng bộ hóa nguyên mẫu (an archetypal synchronization problem )

4 160 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 4
Dung lượng 92,75 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

// process PNP request --lActiveRequests; } Tôi chắc chắn là bạn đoán nhận đã một máy đếm đó như nó phải không phải là một biến tĩnh: nó cần phải là một bộ phận của thiết bị mở rộng của

Trang 1

Vấn đề đồng bộ hóa nguyên

mẫu (An Archetypal Synchronization Problem )

Bởi:

Khoa CNTT ĐHSP KT Hưng Yên

Giả thiết về sau điều đó bạn tăng dần biến này khi bạn nhận được một yêu cầu và sự giảm bớt nó khi bạn sau đó hoàn thành yêu cầu:

NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)

{

++lActiveRequests;

// process PNP request

lActiveRequests;

}

Tôi chắc chắn là bạn đoán nhận đã một máy đếm đó như nó phải không phải là một biến tĩnh: nó cần phải là một bộ phận của thiết bị mở rộng của các bạn vì thế mỗi đối tượng thiết bị đó có máy đếm duy nhất của nó Rẽ sang với tôi, và giả vờ rằng trình điều khiển của các bạn luôn luôn chỉ quản lý một thiết bị đơn Để làm ví dụ đầy đủ ý nghĩa hơn, giả thiết cuối cùng một chức năng đó trong trình điều khiển của các bạn sẽ được gọi là khi nào thời gian của nó để xóa đối tượng thiết bị của các bạn Bạn có lẽ đã muốn trì hoãn thao tác cho đến khi không có nhiều yêu cầu là nổi bật hơn, vì thế bạn có lẽ đã chèn một

sự thử của máy đếm:

NTSTATUS HandleRemoveDevice(PDEVICE_OBJECT fdo, PIRP Irp)

{

Trang 2

<wait for all requests to complete>

IoDeleteDevice(fdo);

}

Ví dụ này mô tả một vấn đề thực sự, nhân tiện, chúng tôi sẽ dùng để thảo luận vấn đề này ở chương 6 trong những yêu cầu của chúng ta của những yêu cầu Plug and Play (PnP) Quản lý vào/ra có thể cố gắng để loại bỏ một trong số những thiết bị của chúng

ta tại một thời điểm khi những yêu cầu được kích hoạt, và chúng tôi cần đề phòng điều

đó bằng việc giữ loại nào đó của máy đếm Tôi sẽ trình bày với bạn ở chương 6 sử dụng IoAcquireRemoveLock như thế và một số chức năng liên quan để giải quyết vấn đề

Một chỗ ẩn núp vấn đề đồng bộ hóa kinh khủng trong những đoạn mã ti chỉ cho bạn thấy, nhưng nó trở nên hiển nhiên chỉ khi bạn nhìn đằng sau sự tăng dần và giảm những thao tác bên trong DispatchPnp Trên một bộ xử lý x86, người biên soạn có lẽ đã thực hiện họ sử dụng những chỉ dẫn này:

; ++lActiveRequests;

mov eax, lActiveRequests

add eax, 1

mov lActiveRequests, eax

; lActiveRequests;

mov eax, lActiveRequests

sub eax, 1

mov lActiveRequests, eax

Để làm rõ vấn đề đồng bộ hóa, giả sử cho rằng đầu tiên có một trực trặc gì đó trong một CPU đơn Hình dung hai luồng đó là cả hai đang cố gắng thử để tiến tới xuyên qua DispatchPnp tại cùng một thời gian Chúng tôi biết họ không phải là cả hai thực hiện đúng đồng thời bởi vì chúng tôi chỉ có một CPU đơn cho họ tới chia sẻ Nhưng hình dung một trong những luồng đó thực hiện gần kết thúc chức năng và quản lý để tải nội dung hiện thời của lActiveRequests vào trong thanh ghi EAX chỉ trước khi luồng khác chặn trước nó Giả thiết lActiveRequests cân bằng với 2 tại lúc đó Như sự chuyển đổi

bộ phận của luồng, hệ điều hành lưa giữ thanh ghi EAX (chứa đựng giá trị 2) như phần của luồng đang rời khỏi ảnh văn cảnh ở đâu đó trong bộ nhớ

Trang 3

Chú ý

Bây giờ hình dung rằng luồng khác quản lý để đưa mã tăng lên qua tại sự bắt đầu của DispatchPnp Nó sẽ tăng dần lActiveRequests từ 2 đến 3 (bởi vì luồng đầu tiên chưa bao giờ được tới cập nhật biến) Nếu luồng đầu tiên chặn trước luồng khác này, hệ điều hành sẽ khôi phục đầu tiên ngữ cảnh của luồng, mà bao gồm giá trị 2 trong thanh ghi EAX Luồng đầu tiên bây giờ thu được trừ 1 từ EAX và cất giữ kết quả sau ở

lActiveRequests Tại điểm này, lActiveRequests chứa đựng giá trị 1, mà sai ở đâu đó xuống là con đường, chúng tôi có lẽ đã hấp tấp xóa đối tượng thiết bị của chúng ta vì chúng tôi có rãnh ghi bị mất thực sự của của một yêu cầu vào/ra

Việc giải quyết vấn đề đặc biệt này thì dễ dàng trên một máy tính x86 — chúng tôi chỉ thay thế nhập/ thêm / cất giữ và nhập/ trừ/ cất giữ những dãy lệnh với những chỉ dẫn nguyên tử:

; ++lActiveRequests;

Trang 4

inc lActiveRequests

; lActiveRequests;

dec lActiveRequests

Trên một Intel x86, những chỉ dẫn INC và DEC không thể được ngắt, ở đó như vậy sẽ chưa bao giờ là một trường hợp trong đó một luồng có thể được chặn trước trong điểm giữa của việc cập nhật máy đếm Trong khi nó đứng, mặc dù, mã này còn là không chắc chắn trong một môi trường bộ đa xử lý bởi vì INC và DEC được thực hiện trong vài bước vi mã Khả dĩ của nó cho 2 CPU khác nhau để đang thực hiện vi mã của họ chỉ yếu

ớt ra khỏi bước sao cho một trong số họ kết thúc lên trên cập nhật một giá trị cũ Vấn

đề Multi-CPU có thể cũng được tránh trong kiến trúc x86 bằng cách sử dụng một tiền tố LOCK:

; ++lActiveRequests;

lock inc lActiveRequests

; lActiveRequests;

lock dec lActiveRequests

Chỉ dẫn LOCK thêm vào đầu những sự khóa ngoài tất cả CPU khác trong khi vi mã cho chỉ dẫn hiện thời thực hiện, do đó bảo đảm sự toàn vẹn dữ liệu

Một cách đáng tiếc, không phải tất cả vấn đề đồng bộ hóa có một giải pháp dễ dàng như vậy Điểm của ví dụ này là không có cách giải quyết như thế nào giải quyết một vấn

đề đơn giản trên một trong những nền tảng nơi Windows XP chạy nhưng phần nào để minh họa hai nguồn của khó khăn: quyền ưu tiên mua của một luồng bởi kẻ khác trong điểm giữa của một sự thay đổi trạng thái và sự thực hiện đồng thời của những thao tác state-change tương phản Chúng tôi có thể tránh khó khăn bằng việc thận trọng sử dụng những nguyên thủy đồng bộ hóa, những đối tượng loại trừ như lẫn nhau như vậy, để ngăn chặn những luồng khác trong khi dữ liệu dùng chung những truy nhập luồng của chúng ta Đôi khi khi sự khóa luồng là không cho phép, chúng tôi có thể tránh quyền

ưu tiên bằng cách sử dụng sơ đồ quyền ưu tiên IRQL, và chúng tôi có thể ngăn ngừa sự thực hiện đồng thời bằng việc thận trọng sử dụng những sự khóa xuay vòng

Ngày đăng: 31/12/2015, 22:14

🧩 Sản phẩm bạn có thể quan tâm

w