Chuyện gì xảy ra mạnh mẽ trước khi có ý nghĩa gì?


9

Cụm từ "mạnh mẽ xảy ra trước đây" được sử dụng nhiều lần trong tiêu chuẩn dự thảo C ++.

Ví dụ: Chấm dứt [basic.start.term] / 5

Nếu việc hoàn thành khởi tạo một đối tượng có thời lượng lưu trữ tĩnh xảy ra mạnh mẽ trước khi gọi đến std :: atexit (xem, [support.start.term]), cuộc gọi đến hàm được chuyển đến std :: atexit được giải trình tự trước khi gọi hàm hủy cho đối tượng. Nếu một lệnh gọi std :: atexit xảy ra mạnh mẽ trước khi hoàn thành việc khởi tạo một đối tượng có thời lượng lưu trữ tĩnh, thì lệnh gọi hàm hủy đối tượng được sắp xếp theo trình tự trước khi lệnh gọi đến hàm được chuyển đến std :: atexit . Nếu một cuộc gọi đến std :: atexit xảy ra mạnh mẽ trước một cuộc gọi khác đến std :: atexit, cuộc gọi đến chức năng được chuyển đến cuộc gọi std :: atexit thứ hai được thực hiện trước khi cuộc gọi đến chức năng được chuyển đến đầu tiên std :: cuộc gọi atexit.

Và được xác định trong các cuộc đua dữ liệu [intro.races] / 12

Đánh giá A xảy ra mạnh mẽ trước khi đánh giá D nếu, hoặc

(12.1) A được giải trình tự trước D, hoặc

(12.2) A đồng bộ hóa với D và cả A và D là các hoạt động nguyên tử nhất quán liên tục ([nguyên tử.order]), hoặc

(12.3) có các đánh giá B và C sao cho A được giải trình tự trước B, B đơn giản xảy ra trước C và C được giải trình tự trước D, hoặc

(12.4) có đánh giá B sao cho A xảy ra mạnh trước B và B mạnh xảy ra trước D.

[Lưu ý: Không chính thức, nếu A xảy ra mạnh mẽ trước B, thì A dường như được đánh giá trước B trong tất cả các bối cảnh. Mạnh mẽ xảy ra trước khi loại trừ hoạt động tiêu thụ. - lưu ý cuối]

Tại sao "mạnh mẽ xảy ra trước khi" được giới thiệu? Theo trực giác, sự khác biệt và mối quan hệ của nó với "xảy ra trước" là gì?

"A dường như được đánh giá trước B trong tất cả các bối cảnh" trong ghi chú có nghĩa là gì?

(Lưu ý: động lực cho câu hỏi này là ý kiến ​​của Peter Cordes dưới câu trả lời này .)

Dự thảo trích dẫn tiêu chuẩn bổ sung (nhờ Peter Cordes)

Thứ tự và tính nhất quán [nguyên tử.order] / 4

Có một tổng đơn hàng S trên tất cả các hoạt động memory_order :: seq_cst, bao gồm hàng rào, đáp ứng các ràng buộc sau. Đầu tiên, nếu A và B là các hoạt động memory_order :: seq_cst và A xảy ra mạnh mẽ trước B, thì A đứng trước B ở S. Thứ hai, với mọi cặp thao tác nguyên tử A và B trên một đối tượng M, trong đó A được sắp xếp theo thứ tự trước B, bốn điều kiện sau được yêu cầu phải được thỏa mãn bởi S:

(4.1) nếu A và B đều là các hoạt động memory_order :: seq_cst, thì A đứng trước B trong S; và

(4.2) nếu A là một hoạt động memory_order :: seq_cst và B xảy ra trước một memory_order :: seq_cst hàng rào Y, thì A đi trước Y trong S; và

(4.3) nếu một memory_order :: seq_cst fence X xảy ra trước A và B là một hoạt động memory_order :: seq_cst, thì X đi trước B trong S; và

(4.4) nếu bộ nhớ_order :: seq_cst hàng rào X xảy ra trước khi A và B xảy ra trước bộ nhớ_order :: seq_cst hàng rào Y, thì X đi trước Y ở S.


1
Tiêu chuẩn dự thảo hiện tại cũng tham chiếu "A xảy ra mạnh mẽ trước B" như là một điều kiện cho một quy tắc áp dụng cho seq_cst, trong Nguyên tắc 31.4 Thứ tự và tính nhất quán: 4 . Điều đó không có trong tiêu chuẩn C ++ 17 n4659 , trong đó 32.4 - 3 xác định sự tồn tại của một đơn đặt hàng seq_cst phù hợp với các xảy ra trước khi đặt hàng và sửa đổi lệnh cho tất cả các vị trí bị ảnh hưởng ; "mạnh mẽ" đã được thêm vào trong một dự thảo sau này.
Peter Cordes

2
@PeterCordes Tôi nghĩ rằng nhận xét không bao gồm tiêu thụ, nêu rõ HB HB trong tất cả bối cảnh PHÂN BIỆT / Mạnh mẽ và nói về các cuộc gọi đến con trỏ chức năng là một điều gì đó không hay. Nếu một chương trình đa luồng gọi atexit()trong một luồng và trong một luồng exit()khác, thì việc khởi tạo chỉ mang một phụ thuộc dựa trên tiêu dùng là không đủ vì kết quả sau đó khác với nếu exit()được gọi bởi cùng một luồng. Một câu trả lời cũ hơn của tôi liên quan đến sự khác biệt này.
Idillotexist Idillotexist 22/11/19


@IwillnotexistIdonotexist Bạn thậm chí có thể thoát khỏi chương trình MT không? Nó không phải là một ý tưởng cơ bản bị phá vỡ?
tò mò

1
@cquilguy Đó là mục đích của exit(). Bất kỳ luồng nào cũng có thể giết toàn bộ chương trình bằng cách thoát hoặc luồng chính có thể thoát bằng cách return-ing. Nó dẫn đến việc kêu gọi atexit()xử lý và cái chết của tất cả các chủ đề bất cứ điều gì họ đang làm.
Idillotexist Idillotexist

Câu trả lời:


5

Tại sao "mạnh mẽ xảy ra trước khi" được giới thiệu? Theo trực giác, sự khác biệt và mối quan hệ của nó với "xảy ra trước" là gì?

Hãy chuẩn bị tinh thần cho "đơn giản là xảy ra trước đây"! Hãy xem ảnh chụp nhanh hiện tại của cppref https://en.cppreference.com/w/cpp/atomic/memory_order

nhập mô tả hình ảnh ở đây

Có vẻ như "đơn giản là xảy ra trước khi" được thêm vào trong C ++ 20.

Đơn giản là xảy ra trước

Bất kể chủ đề nào, đánh giá A chỉ đơn giản xảy ra - trước khi đánh giá B nếu bất kỳ điều nào sau đây là đúng:

1) A được giải trình tự trước B

2) A đồng bộ hóa với B

3) A đơn giản xảy ra - trước X và X đơn giản xảy ra - trước B

Lưu ý: không có hoạt động tiêu thụ, chỉ đơn giản là xảy ra - trước và xảy ra - trước khi quan hệ là như nhau.

Vì vậy, Simply-HB và HB giống nhau ngoại trừ cách chúng xử lý các hoạt động tiêu thụ. Xem HB

Xảy ra trước

Bất kể chủ đề nào, đánh giá A xảy ra - trước khi đánh giá B nếu bất kỳ điều nào sau đây là đúng:

1) A được giải trình tự trước B

2) Một liên kết xảy ra trước B

Việc triển khai là cần thiết để đảm bảo rằng mối quan hệ xảy ra trước khi xảy ra theo chu kỳ, bằng cách giới thiệu đồng bộ hóa bổ sung nếu cần thiết (chỉ có thể cần thiết nếu có hoạt động tiêu thụ có liên quan, xem Batty et al)

Làm thế nào để họ khác nhau về tiêu thụ? Xem liên chủ đề-HB

Liên chủ đề xảy ra-trước

Giữa các luồng, đánh giá Một liên kết xảy ra trước khi đánh giá B nếu bất kỳ điều nào sau đây là đúng

1) A đồng bộ hóa với B

2) A là thứ tự phụ thuộc trước B

3) ...

...

Một hoạt động được đặt hàng phụ thuộc (nghĩa là sử dụng phát hành / tiêu thụ) là HB nhưng không nhất thiết là Simply-HB.

Tiêu thụ thoải mái hơn thu nhận, vì vậy nếu tôi hiểu chính xác, HB thoải mái hơn Simply-HB.

Xảy ra mạnh mẽ

Bất kể chủ đề nào, đánh giá A xảy ra mạnh mẽ - trước khi đánh giá B nếu bất kỳ điều nào sau đây là đúng:

1) A được giải trình tự trước B

2) A đồng bộ hóa với B và cả A và B là các hoạt động nguyên tử nhất quán tuần tự

3) A được giải trình tự - trước X, X đơn giản xảy ra - trước Y và Y được giải trình tự - trước B

4) A xảy ra mạnh mẽ - trước X và X xảy ra mạnh mẽ - trước B

Lưu ý: không chính thức, nếu A xảy ra mạnh mẽ - trước B, thì A dường như được đánh giá trước B trong tất cả các bối cảnh.

Lưu ý: xảy ra mạnh mẽ - trước khi loại trừ hoạt động tiêu thụ.

Vì vậy, một hoạt động phát hành / tiêu thụ không thể mạnh mẽ-HB.

Phát hành / thu nhận có thể là HB và Simply-HB (vì phát hành / thu thập đồng bộ hóa với) nhưng không nhất thiết phải mạnh mẽ-HB. Bởi vì Strongly-HB đặc biệt nói rằng A phải đồng bộ hóa - với B VÀ là một hoạt động nhất quán liên tục.

                            Is happens-before guaranteed?

                        HB             Simply-HB          Strongly-HB

relaxed                 no                 no                 no
release/consume        yes                 no                 no      
release/acquire        yes                yes                 no
S.C.                   yes                yes                yes

"A dường như được đánh giá trước B trong tất cả các bối cảnh" trong ghi chú có nghĩa là gì?

Tất cả các bối cảnh: Tất cả các luồng / tất cả các CPU đều thấy (hoặc "cuối cùng sẽ đồng ý") theo cùng một thứ tự. Đây là sự đảm bảo cho tính nhất quán tuần tự - một thứ tự sửa đổi tổng thể toàn cầu của tất cả các biến. Mua / phát hành chuỗi chỉ đảm bảo thứ tự sửa đổi nhận thức cho các chủ đề tham gia chuỗi. Chủ đề bên ngoài chuỗi về mặt lý thuyết được phép để xem một thứ tự khác nhau.

Tôi không biết tại sao Strongly-HB và Simply-HB được giới thiệu. Có lẽ để giúp làm rõ làm thế nào để hoạt động xung quanh tiêu thụ? Strongly-HB có một tính chất tốt - nếu một luồng quan sát A mạnh xảy ra trước B, nó biết tất cả các luồng sẽ quan sát cùng một thứ.

Lịch sử tiêu thụ:

Paul E. McKenney chịu trách nhiệm tiêu thụ trong các tiêu chuẩn C và C ++. Tiêu thụ đảm bảo thứ tự giữa gán con trỏ và bộ nhớ mà nó trỏ đến. Nó được phát minh vì DEC Alpha. DEC Alpha có thể suy đoán đặc biệt một con trỏ, do đó nó cũng có một hàng rào bộ nhớ để ngăn chặn điều này. DEC Alpha không còn được sản xuất và ngày nay không có bộ xử lý nào có hành vi này. Tiêu thụ được dự định là rất thoải mái.


1
Tốt đau buồn. Tôi gần như hối hận khi hỏi câu hỏi đó. Tôi muốn quay trở lại để giải quyết các vấn đề C ++ dễ dàng như quy tắc vô hiệu hóa trình lặp, tra cứu tên phụ thuộc đối số, toán tử chuyển đổi do người dùng mẫu xác định, khấu trừ đối số mẫu, khi tra cứu tên trong lớp cơ sở trong thành viên của mẫu và khi bạn có thể chuyển đổi thành một cơ sở ảo khi bắt đầu xây dựng một đối tượng.
tò mò

Re: tiêu thụ. Bạn có cho rằng số phận của việc đặt hàng tiêu dùng được liên kết với số phận của DEC Alpha và không có giá trị nào bên ngoài vòm cụ thể đó không?
curiousguy

1
Đó là một câu hỏi hay. Nhìn vào nó nhiều hơn, về mặt lý thuyết có thể giúp tăng hiệu suất cho các vòm được đặt hàng yếu như ARM và PowerPC. Hãy cho tôi thêm thời gian để xem xét nó.
Humphrey Winnebago

1
Tôi muốn nói rằng tiêu thụ tồn tại bởi vì tất cả các ISA có thứ tự yếu khác ngoài Alpha. Trong Alpha asm, các tùy chọn duy nhất được nới lỏng và thu được (và seq-cst), không phải thứ tự phụ thuộc. mo_consumeđược dự định để tận dụng thứ tự phụ thuộc dữ liệu trên các CPU thực và chính thức hóa trình biên dịch không thể phá vỡ sự phụ thuộc dữ liệu thông qua dự đoán nhánh. ví dụ int *p = load(); tmp = *p;có thể bị phá vỡ bởi trình biên dịch giới thiệu if(p==known_address) tmp = *known_address; else tmp=*p;nếu nó có một số lý do để mong đợi một giá trị con trỏ nhất định là phổ biến. Đó là hợp pháp để thư giãn nhưng không tiêu thụ.
Peter Cordes

@PeterCordes phải ... các vòm có thứ tự yếu phải phát ra một rào cản bộ nhớ để có được, nhưng (về mặt lý thuyết) không phải để tiêu thụ. Có vẻ như bạn nghĩ rằng nếu Alpha không bao giờ tồn tại, chúng ta vẫn sẽ tiêu thụ? Ngoài ra, về cơ bản, bạn đang nói rằng tiêu thụ là một rào cản trình biên dịch (hoặc "tiêu chuẩn").
Humphrey Winnebago
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.