2009-07-05 39 views
18

Win32 api có một tập hợp các chức năng InterlockedXXX để xử lý nguyên tử và đồng bộ các biến đơn giản, tuy nhiên dường như không có bất kỳ hàm InterlockedRead nào, chỉ đơn giản là lấy lại giá trị của biến. Làm thế nào mà?InterlockedRead ở đâu?

MSDN says rằng:

Simple đọc và viết đúng canh biến 32-bit là hoạt động nguyên tử

nhưng cho biết thêm:

Tuy nhiên, truy cập không đảm bảo được đồng bộ hóa. Tuy nhiên, quyền truy cập không đảm bảo được đồng bộ hóa. Nếu hai luồng được đọc và ghi từ cùng một biến, bạn không thể xác định xem một luồng sẽ thực hiện thao tác đọc của nó trước khi luồng khác thực hiện thao tác ghi của nó.

Điều này có nghĩa là, thao tác đọc đơn giản của biến có thể diễn ra trong khi một biến khác có thể diễn ra. Vậy tại sao không có chức năng khóa liên động để đọc một biến?

Tôi đoán giá trị có thể được đọc là kết quả InterlockedThêm 0, nhưng điều đó dường như không đúng cách để đi.

Trả lời

7

Cách thông thường để thực hiện điều này là sử dụng phép so sánh trao đổi (ví dụ: InterlockedCompareExchange64) trong đó cả hai giá trị đều giống nhau. Tôi có một nghi ngờ lén lút điều này có thể được thực hiện hiệu quả hơn so với một số 0 vì một lý do nào đó, nhưng tôi không có bằng chứng để sao lưu này.

Điều thú vị là lớp Interlocked của .NET không đạt được phương thức Read cho đến .NET 2.0. Tôi tin rằng Interlocked.Read được triển khai bằng cách sử dụng Interlocked.CompareExchange. (Lưu ý rằng các tài liệu cho Interlocked.Read tấn công tôi như phần nào gây hiểu lầm - nó nói về nguyên tử, nhưng không biến động, có nghĩa là một cái gì đó rất cụ thể trên NET .. Tôi không chắc chắn những gì mô hình bộ nhớ Win32 đảm bảo về tầm nhìn của các giá trị mới được viết từ một chủ đề khác, nếu có.)

+0

Đối với biến động bạn có dòng Thread.VolatileRead. –

+0

@JS: Có lý do cụ thể nào bạn khuyên InterlockedCompareExchange64 (với sự nhấn mạnh trên 64) không? Interlocked.Read cũng làm việc với các giá trị 64 bit và nói rằng "Phương thức đọc không cần thiết trên các hệ thống 64 bit", có nghĩa là InterlockedCompareExchnage (phiên bản 32 bit) không cần thiết khi đọc các giá trị 32 bit trên máy 32 bit. –

+0

@Remus: Tốt điểm về Thread.VolatileRead, mặc dù tài liệu ngụ ý rằng bạn không cần phải lo lắng * ở tất cả * (thay vì trỏ đến Thread.VolatileRead, mà sẽ có ý nghĩa hơn). @Sause: Không có lý do cụ thể để chọn phiên bản 64 bit, không. Tôi nghĩ rằng có đủ tinh tế ở đây mà tôi không muốn yêu cầu chính xác những gì cần thiết khi cố gắng để có được đi mà không làm bất kỳ điều này. –

7

Tôi nghĩ rằng cách diễn giải của bạn về "không được đồng bộ hóa" là sai. Số lần đọc đơn giản nguyên tử, nhưng bạn phải tự lo cho vấn đề về khả năng hiển thị sắp xếp lại và bộ nhớ. Trước đây được xử lý bằng cách sử dụng hướng dẫn hàng rào ở những vị trí thích hợp, sau đó không phải là vấn đề có đọc (nhưng viết đồng thời tiềm năng phải đảm bảo khả năng hiển thị thích hợp, chức năng được khóa liên động phải do nếu chúng ánh xạ tới hướng dẫn asm LOCKED) .

+0

Rất vui khi nghe những mối quan tâm của tôi không hoàn toàn ngu ngốc :) –

+0

@zvrba: Tôi nghĩ rằng những gì tôi gọi là đồng bộ (thực sự, những gì MSDN gọi đồng bộ) là những gì bạn gọi sắp xếp lại. Dù sao, tôi không thực sự nhìn thấy dòng dưới cùng ở đây là gì. Đây có phải là câu trả lời hoặc nhận xét không? –

+1

Đây là câu trả lời - đọc được khóa liên động (bất kỳ thứ gì có thể) không cần thiết. – zvrba

2

Điểm mấu chốt của toàn bộ cuộc thảo luận này là sự liên kết thích hợp, được devined trong phân vùng I của xxx, trong phần '12.6.2 Alignment':

Built-in datatypes shall be properly aligned, which is defined as follows: 
• 1-byte, 2-byte, and 4-byte data is properly aligned when it is stored at 
    a 1-byte, 2-byte, or 4-byte boundary, respectively. 
• 8-byte data is properly aligned when it is stored on the same boundary 
    required by the underlying hardware for atomic access to a native int. 

Về cơ bản, tất cả các giá trị 32-bit có sự liên kết cần thiết, và trên một nền tảng 64 bit, các giá trị 64 bit cũng có sự liên kết bắt buộc.

Lưu ý mặc dù: Có các thuộc tính để thay đổi rõ ràng bố cục lớp trong bộ nhớ, điều này có thể khiến bạn mất liên kết này. Đây là những thuộc tính cụ thể cho mục đích này, vì vậy, trừ khi bạn đã đặt ra để thay đổi cách bố trí, điều này sẽ không áp dụng cho bạn.

Với cách đó, mục đích của lớp Interlocked là cung cấp các hoạt động (để diễn giải) chỉ có thể được quan sát thấy trong trạng thái 'trước' hoặc 'sau' của chúng. Các hoạt động liên khóa thường chỉ quan tâm khi sửa đổi bộ nhớ (thường là trong một số kiểu so sánh không trao đổi tầm thường). Khi bài viết MSDN bạn tìm thấy cho biết, các hoạt động đọc (khi được căn chỉnh đúng) có thể được coi là nguyên tử ở mọi thời điểm mà không cần đề phòng thêm.

Có những cân nhắc tuy nhiên khác khi giao dịch với các hoạt động đọc:

  • Trên các CPU hiện đại, mặc dù đọc có thể nguyên tử, nó cũng có thể trả về giá trị sai từ một bộ nhớ cache cũ ở đâu đó ... đây là nơi bạn có thể cần phải làm cho trường 'biến động' để có được hành vi mà bạn mong đợi
  • Nếu bạn đang xử lý giá trị 64 bit trên phần cứng 32 bit, bạn có thể cần sử dụng thao tác Interlocked.Read để đảm bảo toàn bộ 64 -giá trị bit được đọc trong một hoạt động nguyên tử duy nhất (nếu không nó có thể được thực hiện như 2 lần đọc 32 bit riêng biệt có thể là fro m hoặc một bên của bản cập nhật bộ nhớ)
  • Việc sắp xếp lại các lần đọc/ghi của bạn có thể khiến bạn không nhận được giá trị bạn mong đợi; trong trường hợp này một số rào cản bộ nhớ có thể cần thiết (hoặc rõ ràng, hoặc thông qua việc sử dụng các hoạt động Interlocked lớp)

ngắn tóm tắt; theo như nguyên tử đi, rất có khả năng những gì bạn đang làm không cần bất kỳ hướng dẫn đặc biệt nào để đọc ... tuy nhiên có thể có những thứ khác bạn cần phải cẩn thận, tùy thuộc vào chính xác bạn đang làm gì.

+0

Không phải là nó để 'volatile' bảo vệ chỉ chống lại" bộ đệm được tạo ra bởi trình biên dịch ", như lưu trữ giá trị trước đó trong sổ đăng ký? Điều đó có nghĩa là 'volatile' vẫn có thể sinh ra dữ liệu cũ do bộ nhớ cache CPU, và chỉ sử dụng' Interlocked' lần đọc sẽ bảo vệ chống lại dữ liệu sau. –