2012-02-29 22 views
20

Hãy xem xét các đoạn mã sau:Làm thế nào để ngăn chặn g ++ tối ưu hóa ra một vòng lặp được kiểm soát bởi một biến có thể được thay đổi bởi một IRQ?

unsigned global; 
while(global); 

global được sửa đổi trong một chức năng được gọi bởi một IRQ. Tuy nhiên, g + + loại bỏ phép thử "không-không-zero" và dịch vòng lặp while thành một vòng lặp vô tận.

Tắt tối ưu hóa trình biên dịch giải quyết vấn đề, nhưng C++ có cung cấp ngôn ngữ xây dựng cho nó không?

+0

@ Styne666: tiêu đề là câu hỏi – Necrolis

+0

Xem thêm http://stackoverflow.com/q/7083482/594137 –

+0

@ Styne666 - thực tiễn không tốt để viết mã cần một cấu hình trình biên dịch cụ thể để hoạt động. Do đó, việc vô hiệu hóa tối ưu hóa không có tùy chọn cho mã sản xuất. – 0xbadf00d

Trả lời

17

Khai báo các biến như volatile:

volatile unsigned global; 

Đây là từ khóa mà nói với trình biên dịch rằng global có thể được sửa đổi trong chủ đề khác nhau và tất cả các tối ưu hóa nên được tắt cho nó.

+1

Có thể cange "tất cả các tối ưu hóa" để "tối ưu hóa nhất định", vì vẫn có nhiều tối ưu hóa có thể được áp dụng. Ví dụ: trong 'global = 5 + 6;', câu lệnh của bạn có thể ngụ ý rằng '5 + 6' không bị giảm. –

+2

Việc thêm trình biến đổi dễ bay hơi không thay đổi mã opcode đã tạo. Nó vẫn chuyển thành một vòng lặp vô tận ... – 0xbadf00d

+0

@SaschaHoll có nó. Bạn có thể đặt 'global' thành' 0' trên một luồng khác và vòng lặp sẽ kết thúc. –

0

Bạn có thể sử dụng GCC thuộc tính trên tờ khai chức năng để vô hiệu hóa tối ưu hóa trên một cơ sở cho mỗi chức năng:

void myfunc() __attribute__((optimize(0))); 

Xem trang GCC Function Attributes để biết thêm thông tin.

+0

Nếu biến phải nằm trong một phần cụ thể của bộ nhớ, hãy sử dụng 'section' [Thuộc tính biến] (http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html) để đặt biến đó một cách chính xác. Bạn cũng có thể cần đánh dấu nó là 'bay hơi'. –

7

Vì bạn đang sử dụng GCC và bạn nói rằng làm cho biến volatile không làm việc, bạn có thể đánh lừa tôi ưu hoa vào suy nghĩ rằng vòng lặp thay đổi biến bằng cách nói dối với trình biên dịch:

while(global) 
    asm volatile("" : "+g"(global)); 

Đây là một tuyên bố lắp ráp nội tuyến nói rằng nó sửa đổi biến (nó được chuyển thành toán hạng đầu vào-đầu ra). Nhưng nó trống rỗng, vì vậy rõ ràng nó không làm bất cứ điều gì trong thời gian chạy. Tuy nhiên, trình tối ưu hóa nghĩ rằng nó thay đổi biến - các lập trình viên nói như vậy, và trình biên dịch, chặn thay thế toán hạng (có nghĩa là thay thế một văn bản bằng văn bản khác), không thực sự quan tâm đến nội dung của assembly nội tuyến và sẽ không làm gì những điều buồn cười với nó.

Và vì cơ thể trống và ràng buộc sử dụng nó là cái chung nhất có sẵn, nên hoạt động đáng tin cậy trên tất cả các nền tảng mà GCC hỗ trợ lắp ráp nội tuyến.

+0

Tôi có thể xác nhận rằng mẹo này thực sự hoạt động! Cảm ơn bạn. –

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