2013-04-23 39 views
21

http://en.cppreference.com/w/cpp/atomic/memory_order, và C++ 11 tài liệu tham khảo trực tuyến khác, xác định memory_order_acquire và memory_order_release như: hoạt độngC++ 11 memory_order_acquire và memory_order_release ngữ nghĩa?

  • Acquire: không đọc trong thread hiện hành có thể được sắp xếp lại trước khi tải này.
  • Thao tác phát hành: không viết trong luồng hiện tại có thể được sắp xếp lại sau cửa hàng này.

này dường như cho phép hậu Acquire-viết được thực hiện trước khi hoạt động được, mà có vẻ lạ quá tôi (ngữ nghĩa hoạt động Acquire/release thông thường hạn chế sự di chuyển của tất cả hoạt động bộ nhớ).

nguồn trực tuyến Cùng (http://en.cppreference.com/w/cpp/atomic/atomic_flag) gợi ý rằng một mutex spinlock có thể được xây dựng sử dụng C Atomics ++ và đề cập ở trên thoải mái quy tắc nhớ đặt hàng:

lock mutex: while (lock.test_and_set(std::memory_order_acquire)) 

unlock mutex: lock.clear(std::memory_order_release);    

Với định nghĩa này của khóa/mở khóa, sẽ không phải là đơn giản mã dưới đây bị phá vỡ nếu memory_order_acquire/phát hành được thực sự được định nghĩa theo cách này (tức là, không cấm sắp xếp lại của hậu Acquire-viết):

Thread1: 
    (0) lock 
    (1) x = 1; 
    (2) if (x != 1) PANIC 
    (3) unlock 

Thread2: 
    (4) lock 
    (5) x = 0; 
    (6) unlock 

là việc thực hiện sau đây có thể: (0) khóa, (1) x = 1, (5) x = 0, (2) P ANIC? Tôi đã bỏ lỡ cái gì?

+0

Bạn nghĩ điều này có thể như thế nào? Thứ tự chính xác của sự kiện (bao gồm cả khóa và mở khóa) mà bạn tưởng tượng là gì? –

+1

Tôi đã thêm khóa vào dấu vết ở trên. Tôi tưởng tượng rằng post-obtain-write tại (5) có thể được thực hiện trước (4). –

Trả lời

20

Việc triển khai mutlock spinlock có vẻ ổn với tôi. Tôi nghĩ rằng họ có định nghĩa về số có đượcphát hành hoàn toàn sai.

Dưới đây là giải thích rõ ràng nhất về các mô hình nhất quán về mua/phát hành mà tôi biết: Gharachorloo; Lenoski; Laudon; Gibbons; Gupta; Hennessy: Memory consistency and event ordering in scalable shared-memory multiprocessors, Int'l Symp Comp Arch, ISCA(17):15-26, 1990, doi 10.1145/325096.325102. (Công cuộc đổi là phía sau tường phí ACM Các liên kết thực tế là một bản sao không đằng sau một tường phí..)

Nhìn vào Điều kiện 3.1 tại mục 3.3 và Hình kèm theo 3:

  • trước khi bình thường tải hoặc truy cập cửa hàng được phép để thực hiện đối với bất kỳ bộ xử lý khác, tất cả các truy cập Acquire trước phải được thực hiện, và
  • trước khi truy cập phát hành được phép thực hiện với đối với bất kỳ bộ xử lý khác, tất cả trước đó bình thường tải một d truy cập cửa hàng phải được thực hiện và
  • quyền truy cập đặc biệt [liên tục] phù hợp với tôn trọng với nhau.

Vấn đề là: mua và giải phóng liên tục tuần tự (tất cả các chủ đề trên toàn cầu đồng ý về thứ tự mua và phát hành đã xảy ra.) Tất cả các chủ đề đều đồng ý rằng nội dung xảy ra giữa việc mua và phát hành trên thread cụ thể đã xảy ra giữa việc mua và phát hành.Nhưng các tải và lưu trữ thông thường sau một bản phát hành được phép di chuyển (bằng phần cứng hoặc trình biên dịch) phía trên bản phát hành và tải và lưu trữ bình thường trước việc mua lại được phép di chuyển (bằng phần cứng hoặc trình biên dịch) sau khi có được.

Trong C++ standard (Tôi đã sử dụng liên kết đến bản nháp tháng 1 năm 2012) phần có liên quan là 1,10 (trang 11 đến 14).

Định nghĩa của xảy ra trước khi được thiết kế để được mô hình hóa sau Lamport; Time, Clocks, and the Ordering of Events in a Distributed System, CACM, 21(7):558-565, Jul 1978. C++ mua lại tương ứng với Lamport của nhận, C++ phiên tương ứng với Lamport của gửi. Lamport đặt tổng số thứ tự trên chuỗi sự kiện trong một chuỗi đơn, trong đó C++ phải cho phép một phần đơn hàng (xem Phần 1.9, Đoạn 13-15, trang 10 cho định nghĩa C++ là được sắp xếp trước.) Tuy nhiên, được sắp xếp theo thứ tự trước khi đặt hàng là khá nhiều điều bạn mong đợi. Các câu lệnh được sắp xếp thứ tự theo thứ tự chúng được đưa ra trong chương trình. Phần 1.9, đoạn 14: "Mọi tính toán giá trị và mặt bên được kết hợp với một biểu thức đầy đủ được sắp xếp trước mỗi giá trị tính toán và e ff ect kết hợp với biểu thức đầy đủ tiếp theo được đánh giá."

Toàn bộ điểm của Mục 1.10 là chương trình dữ liệu đua miễn phí tạo ra cùng giá trị được xác định như thể chương trình được chạy trên máy có bộ nhớ liên tục và không có trình biên dịch sắp xếp lại. Nếu có một cuộc đua dữ liệu thì chương trình không có nghĩa ngữ nghĩa nào cả. Nếu không có cuộc đua dữ liệu thì trình biên dịch (hoặc máy) được phép sắp xếp lại các hoạt động không đóng góp vào ảo ảnh về tính nhất quán tuần tự.

Mục 1.10, đoạn 21 (trang 14) cho biết: Chương trình không phải là dữ liệu đua miễn phí nếu có một cặp truy cập A và B từ các chủ đề khác nhau để phản đối X, ít nhất một trong các truy cập đó một tác dụng phụ, và không A xảy ra - trước B, cũng không B xảy ra trước khi A. Nếu không, chương trình sẽ không có dữ liệu.

Đoạn 6-20 đưa ra định nghĩa rất cẩn thận về mối quan hệ xảy ra trước đó. Định nghĩa chính là Đoạn 12:

"Một đánh giá Một xảy ra trước khi đánh giá B nếu:

  • A được giải mã trước khi B, hoặc
  • Một liên thread xảy ra trước khi B."

Vì vậy, nếu có được (cùng một chuỗi) với bất kỳ tuyên bố nào khác, thì việc mua phải xuất hiện để xảy ra trước tuyên bố đó. (Bao gồm cả nếu tuyên bố đó thực hiện ghi.)

Tương tự như vậy: nếu có nhiều tuyên bố là được trình tự trước (cùng một chuỗi) bản phát hành, thì tuyên bố đó phải xuất hiện trước khi phát hành. (Bao gồm nếu câu lệnh đó chỉ thực hiện tính toán giá trị (đọc).)

Lý do mà các trình biên dịch phép di chuyển tính khác từ sau khi một thông cáo tới trước khi phát hành (hoặc từ trước khi tiếp cận được vào sau một đạt được) là vì thực tế rằng những hoạt động đặc biệt làm không có một mối liên hệ xảy ra trước mối quan hệ (vì chúng nằm ngoài phần quan trọng). Nếu họ chạy đua ngữ nghĩa là không xác định, và nếu họ không đua (vì họ không được chia sẻ) sau đó bạn không thể nói chính xác khi họ đã xảy ra đối với việc đồng bộ hóa.

Đó là một cách rất dài để nói rằng: định nghĩa của cppreference.com về việc mua và phát hành là sai. Chương trình ví dụ của bạn không có điều kiện chạy dữ liệu và PANIC không thể xảy ra.

+0

Cảm ơn. Tôi quen thuộc với bài báo - đây là nguồn gốc của sự nhầm lẫn của tôi: có được các ngữ nghĩa truy cập/hoạt động thường đảm bảo rằng cả tải và các cửa hàng sau (theo thứ tự chương trình) thực sự xuất hiện như được thực hiện sau khi có được op. cppreference tuy nhiên dường như cho phép viết để xuất hiện như được thực hiện trước đây. –

+0

Tôi vẫn chưa hoàn toàn bị thuyết phục. Các sửa đổi đối với 'x' không phải là một đối tượng nguyên tử, và do đó không phải là" các hiệu ứng phụ có thể nhìn thấy ". Kết quả là tôi nghĩ một trình biên dịch có thể sắp xếp lại hoặc loại bỏ các phép toán thành x do "quy tắc as-if" 1.9/1. (Mặc dù trong ví dụ cụ thể này, nhiều khả năng trình biên dịch sẽ tối ưu hóa x và cuộc gọi đến PANIC hoàn toàn cho rằng việc truyền liên tục x vào kiểm tra 'if' cho phép loại bỏ hoàn toàn lệnh gọi' PANIC' và cửa hàng trong chuỗi 2 –

+0

Các sửa đổi đối với 'x' là các hiệu ứng phụ có thể nhìn thấy. Nó chỉ là một câu hỏi của _when_ các tác dụng phụ trở nên hiển thị đối với các chủ đề khác Tôi nghĩ về nó như: Các hoạt động phát hành" phát sóng "khả năng hiển thị của bên không nguyên tử Khi các chủ đề của CedomirSegulja 1 thực hiện (0) khóa nó ngay bây giờ phải tin rằng Thread 2 vẫn chưa đạt đến (4) hoặc Thread 2 Tôi đã viết lại (6) –

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