2010-02-26 57 views
6

Tôi đang viết một ứng dụng C++.C++ biến đa luồng biến động

Tôi có biến lớp có nhiều hơn một chuỗi đang ghi.

Trong C++, mọi thứ có thể được sửa đổi mà không có trình biên dịch "nhận ra" rằng nó đang được thay đổi cần phải được đánh dấu dễ bay hơi phải không? Vì vậy, nếu mã của tôi là đa luồng, và một sợi có thể ghi vào một var trong khi một số khác đọc từ nó, tôi có cần đánh dấu var volaltile không?

[Tôi không có điều kiện chủng tộc vì tôi đang dựa vào việc ghi vào ints là nguyên tử]

Cảm ơn!

+9

Điều gì khiến bạn nghĩ rằng viết sẽ là nguyên tử? – bmargulies

+4

Tôi không có chuyên gia về đa luồng, nhưng tôi sẽ luôn thực hiện khóa xung quanh bất kỳ tài nguyên được chia sẻ nào ... –

+0

Tôi đã thực hiện loại điều này trên bộ xử lý lõi đơn PowerPC được nhúng và nó hoạt động đáng tin cậy. Tốt hơn không làm bất kỳ đọc-sửa-ghi (chẳng hạn như '++ sharedInt') nếu nó có thể là hai chủ đề có quyền ghi. (Trên thực tế, nếu hai chủ đề có thể viết, nó có thể chỉ hữu ích nếu bạn giới hạn ** khi ** họ có thể viết. Ví dụ, thread A được phép thay đổi 'sharedInt' từ 0 đến 1 trong khi thread B được phép thay đổi nó từ 1 0.) – Dan

Trả lời

3

dễ bay hơi hướng dẫn trình biên dịch không tối ưu hóa khi "trực giác" của giá trị hoặc sử dụng biến vì nó có thể tối ưu hóa "từ bên ngoài".

dễ bay hơi sẽ không cung cấp bất kỳ đồng bộ hóa nào và giả định viết cho int là nguyên tử là tất cả nhưng thực tế!

Tôi đoán chúng ta cần phải xem một số cách sử dụng để biết liệu có cần thiết biến động trong trường hợp của bạn không (hoặc kiểm tra hành vi của chương trình của bạn) hoặc quan trọng hơn nếu bạn thấy một số loại đồng bộ hóa.

+0

Đó là không đúng, khi bạn đang xây dựng ứng dụng/thuật toán HPC, bạn thường khá ý thức về kiến ​​trúc mà bạn sẽ làm việc. Và do đó bạn sẽ không thêm một khóa vô dụng, nếu bạn không cần nó. – Ben

+0

Vâng hum, quan điểm của tôi ít nhất. – Ben

+0

Tôi luôn luôn nghĩ rằng viết một int là một op nguyên tử (ít nhất là trên CPU x86). Bạn có một số tài liệu tốt về ops nguyên tử? –

0

Nếu không có khóa, bạn vẫn có thể nhận được đơn đặt hàng lại 'không thể' được thực hiện bởi trình biên dịch hoặc bộ xử lý. Và không có gì đảm bảo rằng viết cho int là nguyên tử.

Sẽ tốt hơn nếu sử dụng khóa thích hợp.

13

C++ chưa có bất kỳ điều khoản nào cho đa luồng. Trong thực tế, volatile không làm những gì bạn có ý nghĩa (nó đã được thiết kế cho bộ nhớ adressed phần cứng và trong khi hai vấn đề là tương tự họ là đủ khác nhau mà dễ bay hơi không làm điều đúng - lưu ý rằng dễ bay hơi đã được sử dụng trong khác ngôn ngữ để sử dụng trong bối cảnh mt).

Vì vậy, nếu bạn muốn viết một đối tượng trong một chuỗi và đọc nó trong một chuỗi khác, bạn sẽ phải sử dụng các tính năng đồng bộ mà nhu cầu triển khai của bạn cần khi cần. Đối với một trong những tôi biết, chơi dễ bay hơi không có vai trò trong đó.

FYI, tiêu chuẩn tiếp theo sẽ tính đến MT và dễ bay hơi sẽ không đóng vai trò gì trong đó. Vì vậy, điều đó sẽ không thay đổi. Bạn sẽ chỉ có các điều kiện được xác định tiêu chuẩn trong đó đồng bộ hóa là cần thiết và cách xác định tiêu chuẩn để đạt được chúng.

+0

"Trong thực tế, dễ bay hơi không làm những gì bạn có ý nghĩa". Gì?? Dễ bay hơi được thiết kế để ngăn chặn tối ưu hóa trình biên dịch trên một biến. Nó rất cao, rất, rất khuyến khích cho lập trình đa luồng. Không cố gắng lập trình đa luồng mà không dễ bay hơi. Chương trình của bạn có thể hoạt động tốt trong nhiều năm và đột nhiên gặp sự cố. –

+0

@annoying_squid, xem http://stackoverflow.com/a/2485177/136208. Bắt đầu từ C++ 11, 'std :: atomic <>' có lẽ là cách để có được những gì bạn mặc dù dễ bay hơi sẽ cung cấp. – AProgrammer

-4

Dễ bay hơi sẽ giải quyết được sự cố của bạn, ví dụ: nó sẽ đảm bảo tính nhất quán trong tất cả các bộ đệm của hệ thống. Tuy nhiên nó sẽ không hiệu quả vì nó sẽ cập nhật biến trong bộ nhớ cho mỗi truy cập R hoặc W. Bạn có thể concider bằng cách sử dụng một rào cản bộ nhớ, chỉ khi nào nó là cần thiết, thay vào đó. Nếu bạn đang làm việc với hoặc gcc/icc có cái nhìn về đồng bộ hóa được xây dựng-in: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

EDIT (chủ yếu là về bình luận pm100): Tôi hiểu rằng niềm tin của tôi không phải là một tài liệu tham khảo vì vậy tôi tìm thấy một cái gì đó để báo giá :)

Từ khóa dễ bay hơi được tạo ra để ngăn tối ưu hóa trình biên dịch có thể hiển thị mã không chính xác trong sự hiện diện của các sự kiện không đồng bộ nhất định.Ví dụ,nếu bạn khai báo một biến nguyên thủy như không ổn định, trình biên dịch không được phép cache nó trong một thanh ghi

Từ Dr Dobb's

Thú vị hơn:

lĩnh vực dễ bay hơi là linearizable. Đọc một lĩnh vực dễ bay hơi giống như mua một cái khóa; bộ nhớ làm việc bị vô hiệu và giá trị hiện tại của trường dễ bay hơi được đọc lại từ bộ nhớ. Viết một trường dễ bay hơi giống như giải phóng một khóa: trường biến động được ghi lại ngay lập tức vào bộ nhớ. (điều này là tất cả về tính nhất quán, không phải về số nguyên tử)

từ The Art of lập trình đa, Maurice Herlihy & Nir Shavit

Khóa chứa mã đồng bộ hóa bộ nhớ, nếu bạn không khóa, bạn phải làm điều gì đó và sử dụng từ khóa dễ bay hơi có lẽ là điều đơn giản nhất bạn có thể làm (ngay cả khi nó được thiết kế cho các thiết bị bên ngoài có bộ nhớ gắn với không gian địa chỉ, nó không phải là điểm ở đây)

+0

Tại sao phản hồi này lại bị giảm giá? – anon

+1

vì sai. dễ bay hơi không có gì để làm với bộ nhớ cache. – pm100

+0

@ pm100, Nó không được thiết kế cho điều này tôi đồng ý, nhưng nó đã làm với cache, xem chỉnh sửa của tôi xin vui lòng. – Ben

4

Có, dễ bay hơi là tuyệt đối tối thiểu bạn ' sẽ cần. Nó đảm bảo rằng trình tạo mã sẽ không tạo ra mã lưu trữ biến trong sổ đăng ký và luôn thực hiện đọc và ghi từ/đến bộ nhớ. Hầu hết các trình tạo mã có thể cung cấp đảm bảo nguyên tử trên các biến có cùng kích thước với từ gốc của CPU, chúng sẽ đảm bảo địa chỉ bộ nhớ được căn chỉnh sao cho biến không thể nằm trong ranh giới bộ nhớ cache.

Tuy nhiên, đó không phải là một hợp đồng rất mạnh trên các CPU đa nhân hiện đại. Biến động không không hứa rằng một luồng khác chạy trên lõi khác có thể thấy các cập nhật cho biến đó. Điều đó đòi hỏi một rào cản bộ nhớ, thường là một hướng dẫn mà flushes bộ nhớ cache CPU. Nếu bạn không cung cấp một rào cản, các sợi sẽ có hiệu lực tiếp tục chạy cho đến khi một tuôn ra xảy ra tự nhiên. Điều đó cuối cùng sẽ xảy ra, bộ lập lịch trình chuỗi được ràng buộc để cung cấp một. Điều đó có thể mất một phần nghìn giây.

Khi bạn đã thực hiện các chi tiết như thế này, cuối cùng bạn sẽ phát minh lại biến điều kiện (hay còn gọi là sự kiện) không có khả năng nhanh hơn so với thư viện luồng. Hoặc cũng được thử nghiệm. Không phát minh ra của riêng bạn, luồng là đủ cứng để có được quyền, bạn không cần FUD không chắc chắn rằng nguyên thủy rất cơ bản là rắn.

+2

Dễ bay hơi không phải là mức tối thiểu tuyệt đối. Nó thấp hơn mức tối thiểu. Tối thiểu cũng sẽ phải ngăn chặn đọc/ghi sắp xếp lại xung quanh biến chia sẻ. – jalf

+0

@ jalf - có bao nhiêu điểm tốt hơn dưới mức "tối thiểu tuyệt đối" mà bạn quan tâm? –

+0

Chỉ một: "bên dưới nó";) – jalf

1

Tôi nghĩ rằng volatile chỉ thực sự áp dụng cho việc đọc, đặc biệt là đọc các thanh ghi I/O được ánh xạ bộ nhớ.

Nó có thể được sử dụng để cho trình biên dịch để không cho rằng một khi nó đã đọc từ một vị trí bộ nhớ rằng giá trị sẽ không thay đổi:

while (*p) 
{ 
    // ... 
} 

Trong đoạn mã trên, nếu *p được không được ghi vào trong vòng lặp, trình biên dịch có thể quyết định di chuyển đầu đọc bên ngoài vòng lặp, như thế này:

cached_p=*p 
while (cached_p) 
{ 
    // ... 
} 

Nếu p là một con trỏ đến một cổng I/O bộ nhớ ánh xạ, bạn sẽ muốn phiên bản đầu tiên nơi cổng được kiểm tra trước khi vòng lặp được nhập y thời gian.

Nếu p là con trỏ đến bộ nhớ trong ứng dụng đa luồng, bạn vẫn không được đảm bảo rằng ghi là nguyên tử.

+6

Nó không chỉ là về đọc: "cho (i = 0; i <10; ++ i) {j = i;} có thể được thay thế bằng j = 10; khi j không phải là bay hơi. – stefaanv

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