2012-01-06 66 views
9

Tôi có bộ nhớ dùng chung giữa nhiều quy trình kết nối bộ nhớ theo một cách nhất định. Ví dụ:Truy cập nguyên tử vào bộ nhớ dùng chung

DataBlock { 
int counter; 
double value1; 
double ... } 

Điều tôi muốn cho bộ đếm được cập nhật/tăng lên một cách nguyên tử. Và để phát hành bộ nhớ xảy ra trên địa chỉ đó. Nếu tôi werent sử dụng bộ nhớ chia sẻ, ví dụ, nó sẽ là một cái gì đó giống như

std::atomic<int> counter; 
atomic_store(counter, newvalue, std::memory_order_release); // perform release  operation on the affected memory location making the write visible to other threads 

Làm thế nào để đạt được điều này cho một vị trí bộ nhớ ngẫu nhiên (giải thích được datablock truy cập> ở trên). Tôi có thể đảm bảo địa chỉ được căn chỉnh theo yêu cầu của kiến ​​trúc (x86 linux)

  1. Cập nhật nguyên tử - cách thực hiện? (tức là atomicupdate (addr, newvalue))
  2. Đồng bộ hóa bộ nhớ cho đa lõi - (tức là memorysync (addr)) - cách duy nhất tôi có thể thấy là sử dụng std :: atomic_thread_fence (std :: memory_order_release) - nhưng điều này sẽ "thiết lập bộ nhớ thứ tự đồng bộ hóa của tất cả các cửa hàng nguyên tử và thư giãn nguyên tử "- đó là quá mức cần thiết cho tôi - tôi chỉ muốn vị trí bộ đếm được đồng bộ hóa. Đánh giá cao bất kỳ suy nghĩ nào.
+3

Tôi chỉ suy đoán, nhưng tôi ấn tượng rằng mô hình lập trình C++ không có khái niệm "quy trình" và mô hình bộ nhớ không có khái niệm "bộ nhớ dùng chung", vì vậy tôi nghi ngờ rằng bản thân tiêu chuẩn sẽ tạo ra bất kỳ đảm bảo nào. Bộ nhớ chia sẻ là một tính năng phụ thuộc vào nền tảng, vì vậy hãy tham khảo tài liệu về nền tảng của bạn. –

+0

bạn có thể đặt một 'nguyên tử 'vào trong DataBlock của mình không? Điều đó sẽ hoạt động miễn là 'nguyên tử 'là lockfree (tiêu chuẩn rõ ràng đề cập đến bộ nhớ được chia sẻ giữa các quá trình như một trường hợp sử dụng cho những người đó). Và không có bạn không thể chỉ nhận được một nguyên tử cho một địa chỉ ngẫu nhiên (xem http://stackoverflow.com/questions/8749038/how-to-use-stdatomic-efficiently/8749474) @Kerrek SB: thực tế là kịch bản được đề cập trong [atomics.lockfree] trong bản thảo cuối cùng. – Grizzly

+0

@Grizzly: Bạn có nghĩa là ghi chú không quy định 29.4/3? Rất thú vị, tôi không biết điều đó. –

Trả lời

-2

Bạn có thể sử dụng Khóa & Cơ chế chờ để tăng bộ đếm. Thư viện Boost cung cấp cơ chế Khóa và Chờ. kiểm tra liên kết này cho reference

9

Tôi không thể trả lời với thẩm quyền ở đây, nhưng tôi có thể cung cấp thông tin liên quan có thể hữu ích.

  1. Mutexes có thể được tạo trong bộ nhớ dùng chung và/hoặc được tạo để xử lý chéo. Pthread có một cờ tạo đặc biệt, tôi không thể nhớ nếu nó sử dụng bộ nhớ chia sẻ, hoặc sau đó bạn chia sẻ một xử lý. Linux "futex" có thể sử dụng bộ nhớ chia sẻ trực tiếp (lưu ý địa chỉ người dùng có thể khác nhau, nhưng địa chỉ thực bên dưới phải giống nhau)

  2. Nguyên tử phần cứng hoạt động trên bộ nhớ và không xử lý biến. Đó là, chip của bạn sẽ không quan tâm chương trình nào đang sửa đổi các biến, các nguyên tử mức thấp nhất do đó sẽ tự nhiên được xử lý chéo. Điều tương tự cũng áp dụng cho hàng rào.

  3. C++ 11 không chỉ định nguyên tử xử lý chéo. Tuy nhiên, nếu chúng không có khóa (kiểm tra cờ) thì thật khó để xem trình biên dịch có thể thực hiện chúng như thế nào mà quá trình chéo sẽ không hoạt động. Nhưng bạn sẽ đặt rất nhiều niềm tin vào chuỗi công cụ và nền tảng cuối cùng của bạn.

  4. Đảm bảo phụ thuộc CPU cũng theo dõi địa chỉ bộ nhớ thực, miễn là chương trình của bạn sẽ chính xác ở dạng luồng, cũng phải chính xác ở dạng đa tiến trình (đối với khả năng hiển thị).

  5. Kerrek là chính xác, máy trừu tượng không thực sự đề cập đến nhiều quy trình. Tuy nhiên, các chi tiết đồng bộ hóa của nó được viết theo cách sao cho chúng cũng áp dụng như nhau cho quá trình liên kết khi chúng thực hiện với đa luồng. Điều này liên quan đến # 3: nó sẽ là khó khăn cho một trình biên dịch để vít này lên.

Câu trả lời ngắn gọn, không có tiêu chuẩn nào phù hợp để thực hiện việc này. Tuy nhiên, dựa vào cách tiêu chuẩn xác định các chủ đề mutli có rất nhiều giả định bạn có thể thực hiện cho một trình biên dịch chất lượng.

Câu hỏi lớn nhất là liệu một nguyên tử đơn giản có thể được phân bổ trong bộ nhớ dùng chung (vị trí mới) và công việc hay không. Rõ ràng điều này sẽ chỉ hoạt động nếu nó là một nguyên tử phần cứng thực sự. Tuy nhiên, dự đoán của tôi là với trình biên dịch/thư viện chất lượng, các nguyên tử C++ sẽ hoạt động trong bộ nhớ dùng chung.

Có hành vi xác minh thú vị. :)

4

Kể từ khi bạn đang ở trên Linux, bạn có thể sử dụng gcc nguyên tử tích hợp __sync_fetch_and_add() trên địa chỉ cho counter ... theo gcc-documentation on atomic built-ins, điều này cũng sẽ thực hiện một hàng rào bộ nhớ đầy, không phải là một hoạt động phát hành, nhưng vì bạn thực sự muốn thao tác đọc-sửa-ghi thay vì chỉ đơn giản là tải (tức là tăng bộ đếm không chỉ là tải, nhưng bạn phải đọc, sau đó sửa đổi và cuối cùng ghi lại giá trị), toàn bộ hàng rào bộ nhớ sẽ là lựa chọn tốt hơn để thực thi thứ tự bộ nhớ chính xác cho hoạt động này.

+0

'__sync_fetch_and_add()' có thể được sử dụng, nhưng tôi nghĩ '__sync_sub_and_fetch()' là phù hợp hơn. Bạn giảm số lượng tham chiếu và giải phóng nếu nó giảm xuống 0. Nó đảm bảo rằng nếu hai chủ đề giảm đồng thời từ 2, chỉ có một chủ đề sẽ trả về 0 (và sẽ được giải phóng). – ugoren

+0

Đó chắc chắn là một gợi ý tốt ... một nguyên tử được tích hợp sẵn sẽ được sử dụng để gia tăng trong các bản sao, vv và một để giảm giá trị khi tham chiếu không còn được sử dụng nữa. – Jason

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