2010-04-22 29 views
6

Giả sử tôi có các chức năng không trực tuyến của riêng mình LockMutex và UnlockMutex, đang sử dụng một số mutex thích hợp - chẳng hạn như tăng - bên trong. Trình biên dịch sẽ không biết sắp xếp lại các hoạt động khác liên quan đến các cuộc gọi tới LockMutex và UnlockMutex như thế nào? Nó không thể biết làm thế nào tôi sẽ thực hiện các chức năng này trong một số đơn vị biên dịch khác.Trình biên dịch sắp xếp lại xung quanh ranh giới mutex?

void SomeClass::store(int i) 
{ 
    LockMutex(_m); 
    _field = i; // could the compiler move this around? 
    UnlockMutex(_m); 
} 

ps: Người ta phải sử dụng các lớp học để giữ khóa để đảm bảo mở khóa. Tôi đã bỏ điều này ra để đơn giản hóa ví dụ.

Trả lời

2

Nó không thể nào biết làm thế nào tôi sẽ thực hiện các chức năng này trong một số đơn vị biên dịch khác.

Đây là chìa khóa - vì trình biên dịch không thể biết (nói chung) về việc thực hiện các cuộc gọi hàm, nó không thể di chuyển cửa hàng đến _field bên ngoài các cuộc gọi chức năng đó.

Nói chung, vì _field có thể truy cập bên ngoài SomeClass::store() (không phải là cục bộ), trình biên dịch không thể biết được chức năng bên ngoài có sửa đổi hay không, do đó phải thực hiện lưu trữ đến _field giữa các điểm chuỗi cuộc gọi chức năng .

Nền tảng phần cứng cơ bản có thể cần một số sự chú ý dưới dạng các rào cản bộ nhớ hoặc bộ nhớ cache bị xóa để xử lý bộ nhớ đệm hoặc các hoạt động ngoài trật tự xảy ra trong phần cứng. Việc triển khai các API mutex của nền tảng sẽ giải quyết các vấn đề đó nếu cần thiết.

0

Nếu trình biên dịch đang hoạt động, đó sẽ là trình biên dịch kém. ;-)

2

Nói chung, trình biên dịch sẽ không di chuyển mã xung quanh trừ khi nó biết chắc chắn rằng làm như vậy sẽ không ảnh hưởng đến hành vi thời gian chạy.

+0

đúng. Trình biên dịch chuyển động mã sẽ có một mô hình phân tích tĩnh về cách chương trình của bạn hoạt động và các phụ thuộc dữ liệu/hoạt động của nó, và nó sẽ bảo toàn các phụ thuộc đó. –

+2

Nói đúng ra, không có bất kỳ sự phụ thuộc nào giữa biến _field, và lời gọi tới LockMutex hoặc UnlockMutex, vì vậy việc bảo quản phụ thuộc không giúp ích gì ở đây. –

0

Nếu trình biên dịch không thể đảm bảo rằng các cuộc gọi chức năng sẽ không có tác dụng phụ sẽ sửa đổi các biến giữa các cuộc gọi, nó không thể di chuyển mã. Nếu biến là một biến cục bộ và bạn chưa bao giờ lấy một tham chiếu hoặc tạo ra một con trỏ tới nó, trình biên dịch có thể giả định nó an toàn để di chuyển; Tôi không biết.

+1

Nếu biến là cục bộ, không biến động và không có con trỏ hoặc tham chiếu được lấy, không có chuỗi nào khác có thể truy cập. Vì vậy, như xa như tham gia một mutex là có liên quan, nó sẽ không quan trọng nếu cửa hàng xảy ra trước, sau hoặc giữa các cuộc gọi chức năng hoặc nếu nó không bao giờ xảy ra. –

+0

@Michael Burr, đó không phải là những gì tôi nói sao?Nếu trình biên dịch đủ tinh vi, nó có thể xác định rằng một biến cục bộ tải/lưu trữ an toàn để sắp xếp lại; cho dù nó có hay không có thể phụ thuộc vào cài đặt trình tối ưu hóa. Tôi đã nhìn vượt ra ngoài giới hạn của câu hỏi, nơi nó là rõ ràng biến là * không * địa phương. Khi được hỏi, nó nằm dưới câu đầu tiên của tôi - trình biên dịch không có cách nào để biết các tác dụng phụ của LockMutex hoặc UnlockMutex, vì vậy nó không thể sắp xếp lại. –

+0

Tôi không đồng ý; Tôi nghĩ tôi đang làm sáng tỏ một thứ dường như không chắc chắn ở phần cuối của câu trả lời. Tôi không có ý cho nó có vẻ tranh cãi nếu đó là cách nó đi qua. –

1

Vì nó được viết, nếu các hàm không nằm trong dòng, trình biên dịch sẽ không di chuyển biến gán, vì cuộc gọi có thể không liên quan đến biến _field, nhưng nó phải bảo toàn thứ tự cuộc gọi nghiêm ngặt. Tuy nhiên, nếu trình biên dịch quyết định nội tuyến các cuộc gọi, tôi nghĩ nó sẽ xử lý chúng như là các khối mã độc lập, nghĩa là nó sẽ chỉ sắp xếp lại các lệnh trong cùng một đơn vị mã (chính chức năng nội tuyến) nhưng không phải như sau mã (gán cho biến _field).

+0

Cảm ơn. Bạn có một liên kết đến tài liệu nói rằng trình biên dịch sắp xếp lại dừng lại ở các ranh giới của các hàm nội tuyến ngay cả? – shojtsy

1

Bạn nói đúng, mã đó là chính xác và an toàn. Mặc dù vậy, tôi đã nghĩ đến một "đoạn mã".

pthread_mutex_lock(&mx) + foo() + pthread_mutex_unlock(&mx); 
Các vấn đề liên quan