Dễ bay hơi so với khóa liên động so với khóa


670

Giả sử một lớp có một public int countertrường được truy cập bởi nhiều luồng. Điều này intchỉ tăng hoặc giảm.

Để tăng lĩnh vực này, nên sử dụng phương pháp nào, và tại sao?

  • lock(this.locker) this.counter++;,
  • Interlocked.Increment(ref this.counter);,
  • Thay đổi công cụ sửa đổi truy cập counterthành public volatile.

Bây giờ tôi đã phát hiện ra volatile, tôi đã loại bỏ nhiều locktuyên bố và việc sử dụng Interlocked. Nhưng có một lý do để không làm điều này?


Đọc luồng trong tài liệu tham khảo C # . Nó bao gồm các phần trong và ngoài câu hỏi của bạn. Mỗi trong số ba có mục đích và tác dụng phụ khác nhau.
spoulson

1
simple-talk.com/blogs/2012/01/24/... bạn có thể thấy việc sử dụng volitable trong mảng, tôi không hoàn toàn hiểu được nó, nhưng nó anouther tham chiếu đến điều này không.
eran otzap

50
Điều này giống như nói rằng "Tôi đã phát hiện ra rằng hệ thống phun nước không bao giờ được kích hoạt, vì vậy tôi sẽ loại bỏ nó và thay thế nó bằng thiết bị báo khói". Lý do không làm điều này là vì nó cực kỳ nguy hiểmmang lại cho bạn gần như không có lợi ích gì . Nếu bạn có thời gian để thay đổi mã thì hãy tìm cách làm cho nó ít đa luồng hơn ! Đừng tìm cách làm cho mã đa luồng trở nên nguy hiểm hơn và dễ bị phá vỡ!
Eric Lippert

1
Nhà tôi có cả vòi phun nước chuông báo khói. Khi tăng bộ đếm trên một chủ đề và đọc nó trên một chủ đề khác, có vẻ như bạn cần cả khóa (hoặc Khóa liên động) từ khóa dễ bay hơi. Sự thật?
yoyo

2
@yoyo Không, bạn không cần cả hai.
David Schwartz

Câu trả lời:


857

Tệ nhất (sẽ không thực sự hoạt động)

Thay đổi modifier tiếp cận của counterđểpublic volatile

Như những người khác đã đề cập, điều này tự nó không thực sự an toàn. Điểm chính volatilelà nhiều luồng chạy trên nhiều CPU có thể và sẽ lưu trữ dữ liệu và hướng dẫn lại thứ tự.

Nếu không volatile , và CPU A tăng một giá trị, thì CPU B có thể không thực sự thấy giá trị tăng đó cho đến một lúc sau, điều này có thể gây ra sự cố.

Nếu có volatile, điều này chỉ đảm bảo hai CPU nhìn thấy cùng một dữ liệu cùng một lúc. Điều đó hoàn toàn không ngăn cản họ xen kẽ các hoạt động đọc và ghi của họ, đây là vấn đề bạn đang cố gắng tránh.

Tốt thứ hai:

lock(this.locker) this.counter++;

Điều này là an toàn để làm (miễn là bạn nhớ đến lockmọi nơi khác mà bạn truy cập this.counter). Nó ngăn chặn bất kỳ luồng nào khác thực thi bất kỳ mã nào khác được bảo vệ bởi locker. Cũng sử dụng khóa, ngăn chặn các vấn đề sắp xếp lại đa CPU như trên, điều này thật tuyệt vời.

Vấn đề là, khóa rất chậm và nếu bạn sử dụng lại lockerở một nơi khác không thực sự liên quan thì cuối cùng bạn có thể chặn các luồng khác mà không có lý do.

Tốt

Interlocked.Increment(ref this.counter);

Điều này là an toàn, vì nó thực sự đọc, tăng và viết trong 'một lần nhấn' mà không thể bị gián đoạn. Vì điều này, nó sẽ không ảnh hưởng đến bất kỳ mã nào khác và bạn cũng không cần phải nhớ khóa ở nơi khác. Nó cũng rất nhanh (như MSDN nói, trên các CPU hiện đại, đây thường chỉ là một lệnh CPU).

Tuy nhiên, tôi không hoàn toàn chắc chắn nếu nó xoay quanh các CPU khác sắp xếp lại mọi thứ hoặc nếu bạn cũng cần kết hợp dễ bay hơi với mức tăng.

Liên khóa:

  1. CÁC PHƯƠNG PHÁP GIẢI QUYẾT ĐƯỢC AN TOÀN AN TOÀN TRÊN MỌI SỐ L CORI HOẶC CPU.
  2. Các phương thức lồng vào nhau áp dụng một hàng rào đầy đủ xung quanh các hướng dẫn mà chúng thực hiện, do đó việc sắp xếp lại không xảy ra.
  3. Các phương thức lồng vào nhau không cần hoặc thậm chí không hỗ trợ truy cập vào trường dễ bay hơi , vì dễ bay hơi được đặt một nửa hàng rào xung quanh các hoạt động trên trường đã cho và lồng vào nhau là sử dụng toàn bộ hàng rào.

Lưu ý: Những gì dễ bay hơi thực sự tốt cho.

volatilekhông ngăn được các loại vấn đề đa luồng này, nó dùng để làm gì? Một ví dụ điển hình là bạn có hai luồng, một luồng luôn ghi vào một biến (nói queueLength) và một luồng luôn đọc từ cùng một biến đó.

Nếu queueLengthkhông dễ bay hơi, luồng A có thể viết năm lần, nhưng luồng B có thể thấy những lần ghi đó bị trì hoãn (hoặc thậm chí có khả năng sai thứ tự).

Một giải pháp sẽ là khóa, nhưng bạn cũng có thể sử dụng dễ bay hơi trong tình huống này. Điều này sẽ đảm bảo rằng chủ đề B sẽ luôn nhìn thấy điều cập nhật nhất mà chủ đề A đã viết. Tuy nhiên, lưu ý rằng logic này chỉ hoạt động nếu bạn có nhà văn không bao giờ đọc và độc giả không bao giờ viết nếu điều bạn đang viết là một giá trị nguyên tử. Ngay sau khi bạn thực hiện một lần đọc-sửa đổi-ghi, bạn cần chuyển đến các hoạt động lồng vào nhau hoặc sử dụng Khóa.


29
"Tôi không hoàn toàn chắc chắn ... nếu bạn cũng cần kết hợp biến động với mức tăng." Chúng không thể được kết hợp AFAIK, vì chúng ta không thể vượt qua biến động bởi ref. Bằng cách trả lời tuyệt vời.
Hosam Aly

41
Thanx nhiều! Chú thích của bạn về "Những gì dễ bay hơi thực sự tốt cho" là những gì tôi đang tìm kiếm và xác nhận cách tôi muốn sử dụng dễ bay hơi.
Jacques Bosch

7
Nói cách khác, nếu một var được khai báo là không ổn định, trình biên dịch sẽ cho rằng giá trị của var sẽ không giữ nguyên (tức là không ổn định) mỗi khi mã của bạn đi qua nó. Vì vậy, trong một vòng lặp như: while (m_Var) {} và m_Var được đặt thành false trong một luồng khác, trình biên dịch sẽ không kiểm tra đơn giản những gì đã có trong một thanh ghi được tải trước đó với giá trị của m_Var nhưng đọc giá trị từ m_Var lần nữa. Tuy nhiên, điều đó không có nghĩa là việc không khai báo biến động sẽ khiến vòng lặp tiếp diễn vô tận - chỉ định biến động chỉ đảm bảo rằng nó sẽ không xảy ra nếu m_Var được đặt thành false trong luồng khác.
Zach Saw

35
@Zach Saw: Theo mô hình bộ nhớ cho C ++, dễ bay hơi là cách bạn mô tả nó (về cơ bản hữu ích cho bộ nhớ ánh xạ thiết bị và không phải là nhiều thứ khác). Trong mô hình bộ nhớ cho CLR (câu hỏi này được gắn thẻ C #) là tính dễ bay hơi sẽ chèn các rào cản bộ nhớ xung quanh việc đọc và ghi vào vị trí lưu trữ đó. Rào cản bộ nhớ (và các biến thể bị khóa đặc biệt của một số hướng dẫn lắp ráp) là bạn nói với bộ xử lý không sắp xếp lại mọi thứ và chúng khá quan trọng ...
Orion Edwards

19
@ZachSaw: Một trường dễ bay hơi trong C # ngăn trình biên dịch C # và trình biên dịch jit thực hiện các tối ưu hóa nhất định sẽ lưu trữ giá trị. Nó cũng đảm bảo chắc chắn về thứ tự đọc và ghi có thể được quan sát ở trên nhiều luồng. Là một chi tiết triển khai, nó có thể làm như vậy bằng cách đưa ra các rào cản bộ nhớ khi đọc và ghi. Các ngữ nghĩa chính xác được đảm bảo được mô tả trong đặc tả; lưu ý rằng đặc tả không đảm bảo rằng một thứ tự nhất quán của tất cả các ghi và đọc dễ bay hơi sẽ được quan sát bởi tất cả các luồng.
Eric Lippert

147

EDIT: Như đã lưu ý trong các bình luận, ngày nay tôi rất vui khi sử dụng Interlockedcho các trường hợp của một biến duy nhất trong đó rõ ràng là ổn. Khi nó trở nên phức tạp hơn, tôi vẫn sẽ quay lại khóa ...

Sử dụng volatilesẽ không giúp ích khi bạn cần tăng - bởi vì đọc và viết là các hướng dẫn riêng biệt. Một chủ đề khác có thể thay đổi giá trị sau khi bạn đọc nhưng trước khi bạn viết lại.

Cá nhân tôi hầu như luôn luôn khóa - dễ dàng hơn để đi đúng theo cách rõ ràng là đúng hơn là biến động hoặc Liên khóa. Theo như tôi quan tâm, đa luồng không khóa là dành cho các chuyên gia luồng thực sự, trong đó tôi không phải là một. Nếu Joe Duffy và nhóm của anh ấy xây dựng những thư viện đẹp, sẽ song song mọi thứ mà không bị khóa nhiều như thứ tôi xây, thì thật tuyệt vời, và tôi sẽ sử dụng nó trong tích tắc - nhưng khi tôi tự mình xâu chuỗi, tôi sẽ cố gắng giữ cho nó đơn giản


16
+1 để đảm bảo tôi quên đi việc mã hóa không khóa từ bây giờ.
Xaqron

5
Các mã không khóa chắc chắn không thực sự không khóa vì chúng bị khóa ở một số giai đoạn - cho dù ở cấp độ (FSB) xe buýt hoặc interCPU, vẫn có một hình phạt bạn phải trả. Tuy nhiên, khóa ở các mức thấp hơn này thường nhanh hơn miễn là bạn không bão hòa băng thông nơi khóa xảy ra.
Zach Saw

2
Không có gì sai với Interlocked, đó chính xác là những gì bạn đang tìm kiếm và nhanh hơn khóa đầy đủ ()
Jaap

5
@Jaap: Vâng, những ngày này tôi sẽ sử dụng khóa liên động cho một bộ đếm chính hãng. Tôi chỉ không muốn bắt đầu loay hoay tìm cách tương tác giữa nhiều bản cập nhật không khóa với các biến.
Jon Skeet

6
@ZachSaw: Nhận xét thứ hai của bạn nói rằng các hoạt động lồng vào nhau "khóa" ở một số giai đoạn; Thuật ngữ "khóa" thường ngụ ý rằng một tác vụ có thể duy trì quyền kiểm soát độc quyền tài nguyên trong một khoảng thời gian không giới hạn; lợi thế chính của lập trình không khóa là nó tránh được nguy cơ tài nguyên trở nên không sử dụng được do kết quả của nhiệm vụ sở hữu bị cấm. Đồng bộ hóa bus được sử dụng bởi lớp lồng vào nhau không chỉ "nói chung là nhanh hơn" - trên hầu hết các hệ thống, nó có thời gian trong trường hợp xấu nhất bị ràng buộc, trong khi các khóa thì không.
supercat

44

" volatile" không thay thế Interlocked.Increment! Nó chỉ đảm bảo rằng biến không được lưu trong bộ nhớ cache, nhưng được sử dụng trực tiếp.

Tăng một biến đòi hỏi thực sự ba thao tác:

  1. đọc
  2. tăng
  3. viết

Interlocked.Increment thực hiện cả ba phần như một hoạt động nguyên tử duy nhất.


4
Nói một cách khác, các thay đổi lồng vào nhau được rào chắn đầy đủ và như vậy là nguyên tử. Các thành viên dễ bay hơi chỉ được rào chắn một phần và do đó không đảm bảo an toàn cho chuỗi.
JoeGeeky

1
Trên thực tế, volatilekhông không chắc chắn rằng các biến không được lưu trữ. Nó chỉ đặt ra các hạn chế về cách nó có thể được lưu trữ. Ví dụ, nó vẫn có thể được lưu trong bộ nhớ cache trong bộ nhớ cache L2 của CPU vì chúng được kết hợp chặt chẽ trong phần cứng. Nó vẫn có thể được bắt đầu. Các bài viết vẫn có thể được đăng lên bộ đệm, v.v. (Mà tôi nghĩ là những gì Zach đã nhận được.)
David Schwartz

42

Khóa hoặc gia tăng lồng vào nhau là những gì bạn đang tìm kiếm.

Tính dễ bay hơi chắc chắn không phải là thứ bạn đang theo đuổi - nó chỉ đơn giản là yêu cầu trình biên dịch coi biến luôn luôn thay đổi ngay cả khi đường dẫn mã hiện tại cho phép trình biên dịch tối ưu hóa việc đọc từ bộ nhớ.

ví dụ

while (m_Var)
{ }

nếu m_Var được đặt thành false trong một luồng khác nhưng nó không được khai báo là không ổn định, trình biên dịch sẽ tự do biến nó thành một vòng lặp vô hạn (nhưng không có nghĩa là nó sẽ luôn như vậy) bằng cách kiểm tra nó đối với thanh ghi CPU (ví dụ EAX vì đó là những gì m_Var đã được tải xuống ngay từ đầu) thay vì phát hành một lần đọc khác vào vị trí bộ nhớ của m_Var (điều này có thể được lưu trong bộ nhớ cache - chúng tôi không biết và không quan tâm và đó là điểm kết hợp bộ nhớ cache của x86 / x64). Tất cả các bài đăng trước đó bởi những người khác đã đề cập sắp xếp lại hướng dẫn chỉ đơn giản cho thấy họ không hiểu kiến ​​trúc x86 / x64. Dễ bay hơi khôngvấn đề đọc / ghi các rào cản như được ngụ ý bởi các bài viết trước đó nói rằng 'nó ngăn chặn sắp xếp lại'. Trên thực tế, một lần nữa nhờ vào giao thức MESI, chúng tôi được đảm bảo rằng kết quả mà chúng tôi đọc luôn giống nhau trên các CPU bất kể kết quả thực tế đã được đưa vào bộ nhớ vật lý hay chỉ đơn giản là nằm trong bộ đệm của CPU cục bộ. Tôi sẽ không đi quá sâu vào chi tiết về điều này nhưng hãy yên tâm rằng nếu điều này xảy ra, Intel / AMD có thể sẽ đưa ra lệnh thu hồi bộ xử lý! Điều này cũng có nghĩa là chúng tôi không phải quan tâm đến việc thực hiện đơn hàng, v.v. Kết quả luôn được đảm bảo để nghỉ hưu theo thứ tự - nếu không chúng tôi bị nhồi!

Với Gia tăng liên khóa, bộ xử lý cần phải ra ngoài, lấy giá trị từ địa chỉ đã cho, sau đó tăng và ghi lại - tất cả điều đó trong khi có quyền sở hữu độc quyền toàn bộ dòng bộ đệm (khóa xadd) để đảm bảo không có bộ xử lý nào khác có thể sửa đổi Giá trị của nó.

Với tính không ổn định, bạn vẫn sẽ kết thúc chỉ với 1 hướng dẫn (giả sử JIT hoạt động hiệu quả như bình thường) - inc dword ptr [m_Var]. Tuy nhiên, bộ xử lý (cpuA) không yêu cầu quyền sở hữu độc quyền của dòng bộ đệm trong khi thực hiện tất cả những gì đã làm với phiên bản khóa liên động. Như bạn có thể tưởng tượng, điều này có nghĩa là các bộ xử lý khác có thể ghi giá trị cập nhật trở lại m_Var sau khi được cpuA đọc. Vì vậy, thay vì bây giờ đã tăng giá trị hai lần, bạn kết thúc chỉ với một lần.

Hy vọng điều này làm sáng tỏ vấn đề.

Để biết thêm thông tin, hãy xem 'Hiểu tác động của các kỹ thuật khóa thấp trong các ứng dụng đa luồng' - http://msdn.microsoft.com/en-au/magazine/cc163715.aspx

ps Điều gì đã thúc đẩy trả lời rất muộn này? Tất cả các câu trả lời rất không chính xác (đặc biệt là câu trả lời là câu trả lời) trong phần giải thích của họ, tôi chỉ phải làm rõ cho bất kỳ ai khác đọc nó. nhún vai

pps Tôi giả sử rằng mục tiêu là x86 / x64 chứ không phải IA64 (nó có một mô hình bộ nhớ khác). Lưu ý rằng thông số kỹ thuật ECMA của Microsoft bị sai lệch ở chỗ nó chỉ định mô hình bộ nhớ yếu nhất thay vì mô hình bộ nhớ mạnh nhất (tốt hơn là chỉ định theo mô hình bộ nhớ mạnh nhất để phù hợp trên các nền tảng - nếu không thì mã sẽ chạy 24-7 trên x86 / x64 hoàn toàn không thể chạy trên IA64 mặc dù Intel đã triển khai mô hình bộ nhớ mạnh tương tự cho IA64) - Microsoft đã thừa nhận điều này - http://bloss.msdn.com/b/cbrumme/archive/2003/05/17/51445.aspx .


3
Hấp dẫn. Bạn có thể tham khảo điều này? Tôi vui vẻ bỏ phiếu này, nhưng đăng với một số ngôn ngữ tích cực 3 năm sau khi một câu trả lời được bình chọn cao phù hợp với các tài nguyên tôi đã đọc sẽ yêu cầu một bằng chứng hữu hình hơn một chút.
Steven Evers

Nếu bạn có thể chỉ ra phần nào bạn muốn tham khảo, tôi rất vui khi tìm hiểu một số nội dung từ đâu đó (tôi rất nghi ngờ tôi đã cung cấp bất kỳ bí mật thương mại của nhà cung cấp x86 / x64 nào, vì vậy những thứ này có thể dễ dàng có sẵn trên wiki, Intel PRM (hướng dẫn tham khảo của lập trình viên), blog MSFT, MSDN hoặc một cái gì đó tương tự) ...
Zach Saw

2
Tại sao bất cứ ai cũng muốn ngăn CPU lưu vào bộ nhớ cache nằm ngoài tôi. Toàn bộ bất động sản (chắc chắn không đáng kể về kích thước và chi phí) dành riêng để thực hiện đồng bộ bộ đệm hoàn toàn bị lãng phí nếu đó là trường hợp ... Trừ khi bạn không yêu cầu sự kết hợp bộ nhớ cache, chẳng hạn như thẻ đồ họa, thiết bị PCI, v.v. một dòng bộ đệm để ghi thông qua.
Zach Saw

4
Có, tất cả mọi thứ bạn nói là nếu không 100% ít nhất 99% trên nhãn hiệu. Trang web này (hầu hết) khá hữu ích khi bạn đang trong giai đoạn phát triển vội vã trong công việc nhưng thật không may, tính chính xác của các câu trả lời tương ứng với (trò chơi) phiếu bầu là không có. Vì vậy, về cơ bản trong stackoverflow bạn có thể cảm nhận được đâu là sự hiểu biết phổ biến của độc giả chứ không phải nó thực sự là gì. Đôi khi những câu trả lời hàng đầu chỉ là những câu nói vô nghĩa thuần túy - những huyền thoại thuộc loại. Và thật không may, đây là những gì sinh ra trong những người tình cờ đọc được trong khi giải quyết vấn đề. Mặc dù đó là điều dễ hiểu, không ai có thể biết tất cả mọi thứ.
dùng1416420

1
@BenVoigt Tôi có thể tiếp tục và trả lời về tất cả các kiến ​​trúc .NET chạy trên đó, nhưng sẽ mất vài trang và chắc chắn không phù hợp với SO. Tốt hơn hết là giáo dục mọi người dựa trên mô hình mem phần cứng cơ bản .NET được sử dụng rộng rãi hơn so với mô hình tùy ý. Và với ý kiến ​​của tôi 'ở mọi nơi', tôi đã sửa chữa những sai lầm mà mọi người đang mắc phải khi giả sử xóa / vô hiệu hóa bộ đệm, v.v. Họ đã đưa ra các giả định về phần cứng cơ bản mà không chỉ định phần cứng nào.
Zach Saw

16

Chức năng lồng vào nhau không khóa. Chúng là nguyên tử, có nghĩa là chúng có thể hoàn thành mà không có khả năng chuyển đổi ngữ cảnh trong quá trình tăng. Vì vậy, không có cơ hội bế tắc hoặc chờ đợi.

Tôi sẽ nói rằng bạn nên luôn luôn thích nó để khóa và tăng.

Volility rất hữu ích nếu bạn cần ghi vào một luồng để đọc trong một luồng khác và nếu bạn muốn trình tối ưu hóa không sắp xếp lại các hoạt động trên một biến (vì mọi thứ đang diễn ra trong một luồng khác mà trình tối ưu hóa không biết). Đó là một lựa chọn trực giao cho cách bạn tăng lên.

Đây là một bài viết thực sự tốt nếu bạn muốn đọc thêm về mã không khóa và cách tiếp cận đúng để viết nó

http://www.ddj.com/hpc-high-performance-computing/210604448


11

khóa (...) hoạt động, nhưng có thể chặn một luồng và có thể gây ra bế tắc nếu mã khác đang sử dụng cùng một khóa theo cách không tương thích.

Được lồng vào nhau. * Là cách chính xác để làm điều đó ... ít chi phí hơn vì các CPU hiện đại hỗ trợ điều này như một nguyên thủy.

tự nó biến động là không chính xác. Một luồng cố gắng truy xuất và sau đó ghi lại một giá trị đã sửa đổi vẫn có thể xung đột với một luồng khác làm tương tự.


8

Tôi đã làm một số thử nghiệm để xem lý thuyết thực sự hoạt động như thế nào: kennethxu.blogspot.com/2009/05/interlocked-vs-monitor-performance.html . Thử nghiệm của tôi tập trung nhiều hơn vào so sánhExchnage nhưng kết quả cho Tăng là tương tự. Liên khóa là không cần thiết nhanh hơn trong môi trường đa cpu. Dưới đây là kết quả thử nghiệm cho Tăng trên máy chủ CPU 16 năm tuổi. Nghĩ rằng thử nghiệm cũng liên quan đến việc đọc an toàn sau khi tăng, đó là điển hình trong thế giới thực.

D:\>InterlockVsMonitor.exe 16
Using 16 threads:
          InterlockAtomic.RunIncrement         (ns):   8355 Average,   8302 Minimal,   8409 Maxmial
    MonitorVolatileAtomic.RunIncrement         (ns):   7077 Average,   6843 Minimal,   7243 Maxmial

D:\>InterlockVsMonitor.exe 4
Using 4 threads:
          InterlockAtomic.RunIncrement         (ns):   4319 Average,   4319 Minimal,   4321 Maxmial
    MonitorVolatileAtomic.RunIncrement         (ns):    933 Average,    802 Minimal,   1018 Maxmial

Mặc dù vậy, mẫu mã mà bạn đã kiểm tra rất tầm thường - thực sự không có ý nghĩa gì khi thử nghiệm theo cách đó! Điều tốt nhất sẽ là hiểu những gì các phương pháp khác nhau đang thực sự làm và sử dụng phương pháp phù hợp dựa trên kịch bản sử dụng mà bạn có.
Zach Saw

@Zach, cách thảo luận ở đây là về kịch bản tăng bộ đếm theo cách an toàn cho chủ đề. Những kịch bản sử dụng khác là trong tâm trí của bạn hoặc bạn sẽ kiểm tra nó như thế nào? Cảm ơn các bình luận BTW.
Kenneth Xu

Điểm là, đó là một thử nghiệm nhân tạo. Bạn sẽ không ham cùng một vị trí thường xảy ra trong bất kỳ kịch bản thế giới thực nào. Nếu là bạn, thì bạn cũng bị tắc nghẽn bởi FSB (như được hiển thị trong hộp máy chủ của bạn). Dù sao, hãy nhìn vào trả lời của tôi trên blog của bạn.
Zach Saw

2
Nhìn lại nó lần nữa. Nếu nút cổ chai thực sự là với FSB, thì việc thực hiện giám sát sẽ tuân theo cùng một nút cổ chai. Sự khác biệt thực sự là Interlocked đang thực hiện chờ đợi và thử lại bận rộn, điều này trở thành một vấn đề thực sự với hiệu suất cao. Ít nhất tôi hy vọng bình luận của tôi nêu lên sự chú ý rằng Interlocked không phải lúc nào cũng là lựa chọn đúng đắn để đếm. Thực tế mọi người đang xem xét các giải pháp thay thế cũng giải thích nó. Bạn cần một trình bổ sung dài gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/
Kenneth Xu

8

3

Tôi muốn thêm vào được đề cập trong câu trả lời khác chênh lệch giữa volatile, Interlockedlock:

Từ khóa dễ bay hơi có thể được áp dụng cho các trường thuộc các loại sau:

  • Các loại tham khảo.
  • Các loại con trỏ (trong một bối cảnh không an toàn). Lưu ý rằng mặc dù con trỏ có thể không ổn định, nhưng đối tượng mà nó trỏ đến không thể. Nói cách khác, bạn không thể khai báo "con trỏ" là "dễ bay hơi".
  • Loại đơn giản như sbyte, byte, short, ushort, int, uint, char, float, và bool.
  • Một kiểu enum với một trong những loại cơ sở sau: byte, sbyte, short, ushort, inthoặc uint.
  • Các tham số loại chung được biết đến là các loại tham chiếu.
  • IntPtrUIntPtr.

Các loại khác , bao gồm doublelong, không thể được đánh dấu là "dễ bay hơi" vì đọc và ghi vào các trường của các loại đó không thể được đảm bảo là nguyên tử. Để bảo vệ quyền truy cập đa luồng vào các loại trường đó, hãy sử dụng các Interlockedthành viên lớp hoặc bảo vệ quyền truy cập bằng cách sử dụng lockcâu lệnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.