2015-07-17 17 views
5

Tôi tình cờ đào sâu vào C và khóa lập trình miễn phí. Tôi không biết gcc đảm bảo có thể cho tôi biết rằng một chương trình được thực thi giống như cách tôi viết nó xuống và không có tối ưu đăng ký nào được thực hiện trong một bước nào đó và không có thao tác nào được thay đổi trong thứ tự của nó.Đảm bảo đặt hàng trong GCC

Như tôi hiện đang hiểu nó, nó đảm bảo rằng hoạt động bộ nhớ xảy ra theo thứ tự rất giống nhau và các cuộc gọi phương thức xảy ra theo cùng thứ tự cùng với chính chúng và hoạt động bộ nhớ. Giữa việc sắp xếp lại có thể có dấu vết.

Tối ưu hóa đăng ký có thể được tắt bằng cách sử dụng từ khóa dễ bay hơi.

Có bất kỳ bảo đảm bổ sung hoặc trường hợp góc nào mà C và đặc biệt là gcc ngụ ý không?

+0

AFAIK trình biên dịch chỉ yêu cầu không thay đổi ý nghĩa (tức là hành vi quan sát bên ngoài) của chương trình. Là lập trình viên C bạn không thể thực sự kiểm soát các hoạt động bộ nhớ (trình biên dịch có thể bỏ qua hoặc chèn một hoạt động). Ngay cả khi trình biên dịch chỉ phát ra mã như bạn đã viết nó, nó là không sử dụng. Bạn nên đọc [Out Of Order Execution] (https://en.wikipedia.org/wiki/Out-of-order_execution) và [Memory barriers] (https://en.wikipedia.org/wiki/Memory_barrier), cùng với các hướng dẫn tuần tự hóa và nguyên tử để biết thêm thông tin. –

+1

Tiêu chuẩn C cho phép thực hiện một số quyền tự do để thực hiện lại các hoạt động. Tôi không nghĩ rằng có một điều duy nhất được xác định rõ đó là 'chính xác cách tôi viết nó xuống'. Vì vậy, nó sẽ thực thi theo cùng một cách mọi lúc - có (mã được biên dịch định nghĩa một thứ tự thực hiện cố định). Có phải đó chính là cách bạn viết xuống - không xác định. – Persixty

+2

Câu trả lời ngắn gọn: không có gì đảm bảo. –

Trả lời

1

Nếu mã của bạn phụ thuộc vào việc không sắp xếp lại các hoạt động và không tối ưu hóa nào khác, nó đơn giản là "hành vi không xác định".

Nếu bạn tìm kiếm những bảo đảm như vậy, bạn chỉ cần tìm kiếm một đảm bảo rằng bạn viết một chương trình bị hỏng thực thi chính xác. Bạn nên sử dụng ngữ nghĩa được thể hiện bằng ngôn ngữ bạn đã sử dụng. Nếu bạn cần giả định về cách ngôn ngữ thực hiện các hành động trên một hệ điều hành và máy đã cho, bạn hoàn toàn nằm trên đường dẫn sai!

Nếu bạn thực sự có một số loại bảo đảm cho phiên bản trình biên dịch thực tế và hệ điều hành lớp lót được sử dụng, điều này sẽ không được đảm bảo trong tính năng này! Vì vậy, từ ngữ "đảm bảo" cũng không thực sự đúng. Nếu câu trả lời đơn giản là: Không có gì đảm bảo cả! Ngôn ngữ có ngữ nghĩa và trình biên dịch đảm bảo thực hiện nó. Không còn gì nữa !.

+0

Vì vậy, về cơ bản tôi thậm chí không có đảm bảo rằng thiết lập một con trỏ và thiết lập các điểm khác với các giá trị độc lập xảy ra trong thứ tự rất giống nhau. Điều đó sẽ làm cho hầu hết các triển khai cho các cơ sở dữ liệu miễn phí khóa trong C và C++ bị phá vỡ bởi thiết kế. Tìm những giả định đó ngay cả trong việc triển khai tham chiếu đặc biệt nếu người ta nghĩ về các trình biên dịch cho các phương thức nội tuyến một cách ngẫu nhiên (không thể đoán trước) sẽ bị phá vỡ. Vì vậy, tất cả những libs bị hỏng? –

+0

Đúng là thiết lập hai con trỏ không liên quan có thể được sắp xếp lại và cũng được tối ưu hóa. Nếu một số thư viện phụ thuộc vào điều này, chúng bị hỏng bởi thiết kế. NHƯNG: Nếu có bất kỳ cơ chế khóa tự do nào bên trong có một nơi mà hai con trỏ được so sánh hoặc sử dụng theo bất kỳ cách nào khác. Tại nơi này ngữ nghĩa đảm bảo rằng cả hai con trỏ được thiết lập (hoặc phép toán so sánh được tối ưu hóa theo bất kỳ cách nào khác để hoàn thành ngữ nghĩa của mã). Vì vậy, không có gì liên quan đến sắp xếp lại. Không đưa cho chúng tôi một ví dụ về mã của bạn mà bạn nhìn vào, chúng tôi không thể cung cấp cho bạn câu trả lời nếu nó đúng! – Klaus

1

Trình biên dịch chỉ yêu cầu không thay đổi ý nghĩa của chương trình.

Ý nghĩa của một chương trình được đưa ra bởi ngữ nghĩa của các câu lệnh C của nó, ví dụ: volatile vòng loại là một cách để tái xác nhận ở cấp độ ngữ nghĩa tương tác với các tác nhân bên ngoài.
volatile một mình tuy nhiên là vô dụng khi nói đến đồng bộ hóa chủ đề, nó chỉ có hiệu lực cục bộ. Vì vậy, bạn chỉ nên ngụ ý những gì tiêu chuẩn của C ngụ ý, nếu tiêu chuẩn không đưa ra ngữ nghĩa đặt hàng cho một tuyên bố cũng như bất kỳ tác dụng phụ nào, thì không có gì cả.

Để tối ưu hóa một số mã, trình biên dịch phải chứng minh rằng tối ưu hóa không thay đổi ý nghĩa.
Điều này nói chung là một vấn đề khó khăn (hoặc thậm chí không thể giải quyết), do đó, nó được thực hiện chỉ trong bối cảnh đơn giản.

Cân nhắc

#include <stdio.h> 

int simple(const int a, const int b) 
{ 
    int c = a + b;    //3x Memory operation? 
    int d = c*c;    //2x Memory operation? 

    return d+d;     //Memory operation? 

} 

int main() 
{ 
    int a = 0;     //Memory operation? 
    int b = 0;     //Memory operation? 

    a = simple(2, 3);   //Function call + Memory operation? 
    b = simple(3, 4);   //Function call + Memory operation? 

    printf("%d %d\n", a, b); //Function call + 3x Memory operation? 

    return 0; 
} 

Tiêu chuẩn C dictates rằng a = simple(2, 3); được thực hiện trước b = simple(3, 4); như kết thúc một biểu thức là một điểm chuỗi.

Đây là mã được tạo ra bởi gcc với đầy đủ tối ưu hóa

lea 0x18f0(%rip),%rcx  # 0x100403030, "%d %d\n" 
mov $0x62,%r8d         
mov $0x32,%edx         
callq 0x100401110 <printf> 

tôi sử dụng Cygwin, vì vậy ABI là một Windows của.Đây là tương đương với

printf("%d %d\n", 50, 98); 

Đây là một ví dụ đặc biệt, hàm simpletinh khiết và mất thời gian biên dịch thường xuyên biểu, vì vậy kết quả được biết đến tại thời gian biên dịch.
Đây là bằng chứng cho thấy gcc cần thiết để tối ưu hóa các cuộc gọi.


Bằng văn bản khóa mã miễn phí bạn không nên lo lắng về việc tối ưu hóa trình biên dịch ở tất cả miễn là bạn sử dụng ngữ nghĩa chính xác (ví dụ volatile vì có đọc-ghi truy cập như tác dụng phụ vì lợi ích của tối ưu hóa chỉ).

Điều gì bạn thực sự cần phải lo lắng là memory ordering như được nêu trong nhận xét của tôi.
C11 cuối cùng cũng chứng nhận tất cả điều này trong số memory model.

+0

Bạn trả lời sai khi sử dụng từ khóa dễ bay hơi! Không có gì đảm bảo rằng bất kỳ truy cập nào đến biến phụ thuộc vào bất kỳ biến nào khác.Đặc biệt là trên các ứng dụng đa luồng dễ bay hơi chỉ đơn giản là vô dụng. Bạn phải sử dụng bất kỳ loại câu lệnh nào tạo ra các rào cản bộ nhớ để đồng bộ hóa quyền truy cập của bạn vào bộ nhớ. dễ bay hơi không làm điều này! – Klaus

+0

@Klaus đã nói như vậy? 'volatile' được sử dụng để xử lý các truy cập đọc-ghi như các tác dụng phụ vì lợi ích của ** tối ưu hóa **, đọc lại toàn bộ đoạn văn. Tôi đề cập một cách rõ ràng mô hình bộ nhớ của C11 là cách duy nhất để đồng bộ hóa các luồng. –

+0

Bạn đã viết "tác nhân bên ngoài" có thể bị hiểu lầm bởi tôi. Điều duy nhất 'dễ bay hơi 'là hữu ích là nói một cái gì đó như" bộ nhớ có thể được sửa đổi bên ngoài ra khỏi sự kiểm soát của mã nhìn thấy thực tế ". Điều đó không liên quan gì đến rào cản và trật tự của bộ nhớ. Bởi vì OP yêu cầu triển khai lockfree, ông yêu cầu đặc biệt cho đa luồng. Vì vậy, có một nhu cầu cho các rào cản bộ nhớ ở tất cả và dễ bay hơi không phải là một phần hữu ích của câu trả lời. Chỉ có hai xu của tôi. – Klaus

1

Đảm bảo đặt hàng giữa các chủ đề trong C chỉ có thể đạt được với stdatomic.h từ C11 hoặc phần mở rộng dành riêng cho trình biên dịch. Trong tất cả các trường hợp khác, thứ duy nhất mà trình biên dịch cần đảm bảo là hành vi bên ngoài có thể nhìn thấy của chương trình (điều này có thể được dịch thành: các lời gọi hàm và tham chiếu đến bộ nhớ không nằm trong điều khiển trình biên dịch) giống như được diễn giải theo Tiêu chuẩn. Trước khi các chủ đề C11 không tồn tại từ quan điểm của tiêu chuẩn C, do đó, nó không liên quan đến chính nó với hành vi luồng.

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