2013-08-26 46 views
32

Các khái niệm về một hàng rào biên dịch thường đi lên khi tôi đọc về mô hình bộ nhớ, các rào cản, đặt hàng, Atomics, vv, nhưng thông thường nó trong bối cảnh cũng được kết hợp với một hàng rào CPU, như người ta mong đợi.Khi nào thì rào cản bộ nhớ chỉ biên dịch (chẳng hạn như std :: atomic_signal_fence) hữu ích?

Thỉnh thoảng, tôi đọc về cấu trúc hàng rào mà chỉ áp dụng áp dụng cho trình biên dịch. Một ví dụ của việc này là 11 std::atomic_signal_fence C++ chức năng, trong đó nêu tại cppreference.com:

std :: atomic_signal_fence tương đương với std :: atomic_thread_fence, ngoại trừ không CPU hướng dẫn bộ nhớ đặt hàng được ban hành. Chỉ sắp xếp lại các hướng dẫn bởi trình biên dịch bị chặn theo thứ tự hướng dẫn.

tôi có năm câu hỏi liên quan đến chủ đề này:

  1. Như ngụ ý của tên std::atomic_signal_fence, là một không đồng bộ ngắt (chẳng hạn như một sợi được preempted bởi hạt nhân để thực hiện một xử lý tín hiệu) chỉ trường hợp trong đó chỉ có trình biên dịch chỉ hàng rào là hữu ích?

  2. Tính hữu dụng của nó có áp dụng cho tất cả các kiến ​​trúc, bao gồm được đặt hàng được đặt hàng mạnh mẽ như x86 không?

  3. một cụ dụ có thể được cung cấp để chứng minh tính hữu ích của một trình biên dịch chỉ hàng rào?

  4. Khi sử dụng std::atomic_signal_fence, có bất kỳ sự khác biệt nào giữa việc sử dụng acq_relseq_cst yêu cầu không? (Tôi mong chờ nó làm cho không có sự khác biệt.)

  5. Câu hỏi này có thể được bao phủ bởi những câu hỏi đầu tiên, nhưng tôi đủ tò mò muốn hỏi cụ thể về nó anyway: Có bao giờ cần thiết để sử dụng hàng rào với thread_local truy cập? (Nếu nó bao giờ sẽ là, tôi mong chờ trình biên dịch chỉ hàng rào như atomic_signal_fence là công cụ của sự lựa chọn.)

Cảm ơn bạn.

+2

Bạn đã kiểm tra chưa? http://preshing.com/20120625/memory-ordering-at-compile-time. –

+1

Trích dẫn preshing.com: "Như tôi đã đề cập, ** các rào cản trình biên dịch đủ để ngăn bộ nhớ sắp xếp lại trên một hệ thống đơn vi xử lý **. Nhưng đó là năm 2012, và những ngày này, tính toán đa lõi là chuẩn. Nếu chúng ta muốn đảm bảo tương tác xảy ra theo thứ tự mong muốn trong một môi trường đa xử lý, và trên bất kỳ cấu trúc CPU nào, thì rào cản trình biên dịch là không đủ. [...] " –

+1

@chico: Tốt điểm- nếu lập trình viên ** biết ** ứng dụng sẽ * * Chỉ ** chạy trên các hệ thống không phải SMP (ví dụ, CPU đơn với lõi đơn ** hoặc ** SMP bị vô hiệu hóa trong hạt nhân vì một lý do nào đó), đó là thứ mà trình biên dịch không thể biết hoặc giả định, sau đó 'atomic_signal_fence' (hoặc một số cấu trúc hàng rào * chỉ biên dịch * khác) có thể được sử dụng như một tối ưu hóa tiềm năng. Như bài báo nói, hạt nhân Linux có các hàm 'smp_rmb' và' smp_wmb' được thực hiện theo cách này. Tuy nhiên, tôi vẫn quan tâm đến việc nghe (các) câu trả lời - nếu tồn tại - không bị hạn chế với giả thiết như vậy. – etherice

Trả lời

21

Để trả lời tất cả 5 câu hỏi sau:


1) Một hàng rào biên dịch (bởi chính nó, mà không có một hàng rào CPU) chỉ hữu dụng trong hai tình huống:

  • Để thực thi ràng buộc thứ tự bộ nhớgiữa một chuỗi đơn và bộ xử lý ngắt không đồng bộ bou nd đến cùng một luồng (chẳng hạn như trình xử lý tín hiệu).

  • Để thực thi bộ nhớ hạn chế đểgiữa nhiều đề khi nó được đảm bảo rằng tất cả các chủ đề sẽ thực hiện trên cùng một CPU lõi. Nói cách khác, ứng dụng sẽ chỉ chạy trên các hệ thống single core hoặc ứng dụng thực hiện các biện pháp đặc biệt (thông qua processor affinity) để đảm bảo rằng mọi chuỗi chia sẻ dữ liệu đều được liên kết với cùng một lõi.


2) Mô hình bộ nhớ của kiến ​​trúc cơ bản, cho dù đó là strongly- hoặc yếu theo lệnh, không có mang về cho dù một trình biên dịch hàng rào là cần thiết trong một tình huống.


3) Đây là pseudo-code đó chứng tỏ việc sử dụng một hàng rào biên dịch, bởi chính nó, để đủ đồng bộ hóa truy cập bộ nhớ giữa một sợi và một bộ xử lý tín hiệu async ràng buộc với chủ đề tương tự:

void async_signal_handler() 
{ 
    if (is_shared_data_initialized) 
    { 
     compiler_only_memory_barrier(memory_order::acquire); 
     ... use shared_data ... 
    } 
} 

void main() 
{ 
// initialize shared_data ... 
    shared_data->foo = ... 
    shared_data->bar = ... 
    shared_data->baz = ... 
// shared_data is now fully initialized and ready to use 
    compiler_only_memory_barrier(memory_order::release); 
    is_shared_data_initialized = true; 
} 

Lưu ý quan trọng: dụ này giả định rằng async_signal_handler được ràng buộc với chủ đề tương tự mà khởi shared_data và đặt is_initialized cờ, có nghĩa là ứng dụng đơn luồng, hoặc nó đặt threa d mặt nạ tín hiệu cho phù hợp. Nếu không, hàng rào trình biên dịch sẽ không đủ và cần có một hàng rào CPU CPU.


4) Chúng phải giống nhau.acq_relseq_cst cả hai sẽ dẫn đến hàng rào trình biên dịch đầy đủ (hai chiều), không có hướng dẫn CPU liên quan đến hàng rào phát ra. Khái niệm "tính nhất quán tuần tự" chỉ xuất hiện khi có nhiều lõi và chủ đề liên quan, và atomic_signal_fence chỉ liên quan đến một luồng thực thi.


5) số (Trừ khi tất nhiên, các dữ liệu thread-địa phương được truy cập từ một trình xử lý tín hiệu không đồng bộ trong trường hợp này một hàng rào biên dịch có thể là cần thiết.) Nếu không, hàng rào không bao giờ nên cần thiết với chủ đề Dữ liệu địa phương vì trình biên dịch (và CPU) chỉ được phép sắp xếp lại các truy cập bộ nhớ theo các cách không thay đổi hành vi quan sát của chương trình đối với sequence points của nó từ một phối cảnh đơn luồng. Và một cách hợp lý có thể suy nghĩ về các thống kê luồng-địa phương trong một chương trình đa luồng giống như các thống kê toàn cầu trong một chương trình một luồng. Trong cả hai trường hợp, dữ liệu chỉ có thể truy cập từ một chuỗi duy nhất, ngăn chặn cuộc đua dữ liệu xảy ra.

+0

Rất rõ ràng và có nhiều thông tin. +1. – etherice

+1

Thông tin, nhưng không chính xác. Có những trường hợp khác trong đó các hàng rào biên dịch chỉ hữu ích trong mã C11 trước cho các bộ vi xử lý cụ thể. Ví dụ, nếu bạn đang sử dụng x86 và hài lòng với việc phát hành, nhưng muốn cho phép trình biên dịch sắp xếp lại các hoạt động bộ nhớ đến các địa chỉ khác nhau trong một khối, trình biên dịch hàng rào xung quanh khối (nhưng để lại truy cập bộ nhớ nonvolatile) cách để đạt được điều này. – user2949652

2

Có một số thành phần lập trình C không thể thay đổi nhưng hữu ích trong đó hàng rào trình biên dịch có ích, ngay cả trong mã đa lõi (đặc biệt là mã C11 trước). Tình huống điển hình là nơi chương trình đang thực hiện một số truy cập bình thường được tạo ra dễ bay hơi (vì chúng là biến chia sẻ), nhưng bạn muốn trình biên dịch có thể di chuyển các truy cập xung quanh. Nếu bạn biết rằng các truy cập là nguyên tử trên nền tảng đích (và bạn thực hiện một số biện pháp phòng ngừa khác), bạn có thể để các truy cập không biến đổi, nhưng chứa chuyển động mã bằng cách sử dụng các rào cản trình biên dịch.

Rất may, hầu hết các chương trình như thế này đều lỗi thời với nguyên tử C11/C++ 11 thoải mái.

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