Tôi đã nghe nói i ++ không an toàn cho luồng, ++ i có an toàn cho luồng không?


90

Tôi đã nghe nói rằng i ++ không phải là một câu lệnh an toàn cho luồng vì trong assembly, nó giảm việc lưu trữ giá trị ban đầu dưới dạng tạm thời ở đâu đó, tăng nó lên rồi thay thế nó, điều này có thể bị gián đoạn bởi một công tắc ngữ cảnh.

Tuy nhiên, tôi đang thắc mắc về ++ i. Theo như tôi có thể nói, điều này sẽ giảm xuống một lệnh hợp ngữ duy nhất, chẳng hạn như 'thêm r1, r1, 1' và vì nó chỉ là một lệnh nên nó sẽ không thể bị gián đoạn bởi một công tắc ngữ cảnh.

Bất cứ ai có thể làm rõ? Tôi giả định rằng nền tảng x86 đang được sử dụng.


Chỉ là một câu hỏi. Loại kịch bản nào sẽ cần cho hai (hoặc nhiều) luồng truy cập vào một biến như vậy? Ở đây tôi xin thật lòng, không phải chỉ trích. Chỉ là vào giờ này, đầu tôi không nghĩ ra được gì nữa.
OscarRyz

5
Một biến lớp trong một lớp C ++ duy trì một số lượng đối tượng?
paxdiablo

1
Video hay về vấn đề tôi vừa xem hôm nay do một người khác nói với tôi: youtube.com/watch?v=mrvAqvtWYb4
Johannes Schaub - litb

1
được gắn thẻ lại là C / C ++; Java không được xem xét ở đây, C # cũng tương tự, nhưng thiếu ngữ nghĩa bộ nhớ được xác định chặt chẽ như vậy.
Tim Williscroft

1
@Oscar Reyes Giả sử bạn có hai luồng sử dụng biến i. Nếu một luồng chỉ tăng luồng khi nó ở một điểm nhất định và luồng kia chỉ giảm luồng khi nó ở một điểm khác, bạn sẽ phải lo lắng về sự an toàn của luồng.
samoz

Câu trả lời:


157

Bạn đã nghe nhầm. Nó có thể "i++"an toàn theo luồng đối với một trình biên dịch cụ thể và kiến ​​trúc bộ xử lý cụ thể nhưng nó không bắt buộc trong các tiêu chuẩn. Trên thực tế, vì đa luồng không phải là một phần của tiêu chuẩn ISO C hoặc C ++ (a) , bạn không thể coi bất cứ thứ gì là an toàn cho luồng dựa trên những gì bạn nghĩ rằng nó sẽ biên dịch xuống.

Nó khá khả thi ++icó thể biên dịch thành một chuỗi tùy ý như:

load r0,[i]  ; load memory into reg 0
incr r0      ; increment reg 0
stor [i],r0  ; store reg 0 back to memory

sẽ không an toàn theo luồng trên CPU (tưởng tượng) của tôi không có hướng dẫn tăng bộ nhớ. Hoặc nó có thể thông minh và biên dịch nó thành:

lock         ; disable task switching (interrupts)
load r0,[i]  ; load memory into reg 0
incr r0      ; increment reg 0
stor [i],r0  ; store reg 0 back to memory
unlock       ; enable task switching (interrupts)

nơi lockvô hiệu hóa và unlockcho phép ngắt. Tuy nhiên, ngay cả khi đó, điều này có thể không an toàn theo luồng trong một kiến ​​trúc có nhiều hơn một trong các CPU này chia sẻ bộ nhớ ( lockchỉ có thể vô hiệu hóa các ngắt cho một CPU).

Bản thân ngôn ngữ (hoặc các thư viện cho nó, nếu nó không được tích hợp sẵn trong ngôn ngữ) sẽ cung cấp các cấu trúc an toàn cho luồng và bạn nên sử dụng những cấu trúc đó thay vì phụ thuộc vào sự hiểu biết của bạn (hoặc có thể hiểu nhầm) về mã máy nào sẽ được tạo.

Những thứ như Java synchronizedpthread_mutex_lock()(có sẵn cho C / C ++ trong một số hệ điều hành) là những gì bạn cần xem xét (a) .


(a) Câu hỏi này được đặt ra trước khi tiêu chuẩn C11 và C ++ 11 được hoàn thành. Những lần lặp đó hiện đã giới thiệu hỗ trợ phân luồng vào các đặc tả ngôn ngữ, bao gồm các kiểu dữ liệu nguyên tử (mặc dù chúng và các luồng nói chung, là tùy chọn, ít nhất là trong C).


8
1 cho nhấn mạnh rằng đây không phải là một vấn đề nền tảng cụ thể, chưa kể đến một câu trả lời rõ ràng ...
RBerteig

2
chúc mừng vì huy hiệu bạc C của bạn :)
Johannes Schaub - litb

Tôi nghĩ bạn nên nói chính xác rằng không có hệ điều hành hiện đại nào cho phép các chương trình ở chế độ người dùng tắt ngắt và pthread_mutex_lock () không phải là một phần của C.
Bastien Léonard

@Bastien, không có hệ điều hành hiện đại sẽ được chạy trên một CPU mà không có một hướng dẫn tăng bộ nhớ :-) Nhưng quan điểm của bạn là đưa về C.
paxdiablo

5
@Bastien: Bull. Các bộ xử lý RISC thường không có hướng dẫn tăng bộ nhớ. Tripplet load / add / stor là cách bạn thực hiện điều đó trên PowerPC.
derobert

42

Bạn không thể đưa ra tuyên bố chung về ++ i hoặc i ++. Tại sao? Xem xét việc tăng số nguyên 64 bit trên hệ thống 32 bit. Trừ khi máy bên dưới có lệnh bốn từ "tải, tăng, lưu", việc tăng giá trị đó sẽ yêu cầu nhiều lệnh, bất kỳ lệnh nào trong số đó có thể bị gián đoạn bởi công tắc ngữ cảnh luồng.

Ngoài ra, ++ikhông phải lúc nào cũng "thêm một vào giá trị". Trong một ngôn ngữ như C, việc tăng con trỏ thực sự thêm kích thước của thứ được trỏ tới. Có nghĩa là, nếu ilà một con trỏ đến cấu trúc ++i32 byte , thêm 32 byte. Trong khi hầu hết tất cả các nền tảng đều có lệnh "gia tăng giá trị tại địa chỉ bộ nhớ" là nguyên tử, không phải tất cả đều có lệnh nguyên tử "thêm giá trị tùy ý vào giá trị tại địa chỉ bộ nhớ".


35
Tất nhiên nếu bạn không giới hạn bản thân với các số nguyên 32-bit nhàm chán, trong một ngôn ngữ như C ++, ++, tôi thực sự có thể là một lệnh gọi đến một dịch vụ web cập nhật một giá trị trong cơ sở dữ liệu.
Nhật thực

16

Cả hai đều không an toàn về luồng.

CPU không thể làm toán trực tiếp với bộ nhớ. Nó thực hiện điều đó một cách gián tiếp bằng cách tải giá trị từ bộ nhớ và thực hiện phép toán với các thanh ghi CPU.

i ++

register int a1, a2;

a1 = *(&i) ; // One cpu instruction: LOAD from memory location identified by i;
a2 = a1;
a1 += 1; 
*(&i) = a1; 
return a2; // 4 cpu instructions

++ tôi

register int a1;

a1 = *(&i) ; 
a1 += 1; 
*(&i) = a1; 
return a1; // 3 cpu instructions

Đối với cả hai trường hợp, có một điều kiện chủng tộc dẫn đến giá trị i không thể đoán trước.

Ví dụ, giả sử có hai luồng ++ i đồng thời với mỗi luồng sử dụng thanh ghi a1, b1 tương ứng. Và, với việc chuyển đổi ngữ cảnh được thực hiện như sau:

register int a1, b1;

a1 = *(&i);
a1 += 1;
b1 = *(&i);
b1 += 1;
*(&i) = a1;
*(&i) = b1;

Kết quả là tôi không trở thành i + 2 mà trở thành i + 1, điều này không chính xác.

Để khắc phục điều này, các CPU moden cung cấp một số loại lệnh LOCK, UNLOCK cpu trong khoảng thời gian chuyển đổi ngữ cảnh bị tắt.

Trên Win32, sử dụng InterlockedIncrement () để thực hiện i ++ để đảm bảo an toàn cho luồng. Nó nhanh hơn nhiều so với việc dựa vào mutex.


6
"CPU không thể làm toán trực tiếp với bộ nhớ" - Điều này không chính xác. Có CPU-s, nơi bạn có thể làm toán "trực tiếp" trên các phần tử bộ nhớ mà không cần phải tải nó vào một thanh ghi trước. Ví dụ. MC68000
darklon 12/12/11

1
Các lệnh LOCK và UNLOCK CPU không liên quan gì đến chuyển mạch ngữ cảnh. Họ khóa các dòng bộ nhớ cache.
David Schwartz

11

Nếu bạn đang chia sẻ thậm chí một int trên các luồng trong môi trường đa lõi, bạn cần có các rào cản bộ nhớ thích hợp. Điều này có thể có nghĩa là sử dụng các hướng dẫn được lồng vào nhau (ví dụ: xem InterlockedIncrement trong win32) hoặc sử dụng một ngôn ngữ (hoặc trình biên dịch) đảm bảo một số luồng an toàn. Với việc sắp xếp lại lệnh và bộ nhớ đệm ở mức CPU và các vấn đề khác, trừ khi bạn có những đảm bảo đó, đừng cho rằng bất kỳ thứ gì được chia sẻ trên các luồng là an toàn.

Chỉnh sửa: Một điều bạn có thể giả định với hầu hết các kiến ​​trúc là nếu bạn đang xử lý các từ đơn được căn chỉnh đúng cách, bạn sẽ không kết thúc với một từ duy nhất có chứa sự kết hợp của hai giá trị được trộn với nhau. Nếu hai lần ghi chồng lên nhau, một lần sẽ thắng và lần còn lại sẽ bị loại bỏ. Nếu bạn cẩn thận, bạn có thể tận dụng điều này và thấy rằng ++ i hoặc i ++ đều an toàn cho luồng trong tình huống một người viết / nhiều người đọc.


Thực tế sai trong môi trường nơi truy cập int (đọc / ghi) là nguyên tử. Có những thuật toán có thể hoạt động trong những môi trường như vậy, mặc dù việc thiếu các rào cản bộ nhớ có thể có nghĩa là đôi khi bạn đang làm việc trên dữ liệu cũ.
MSalters

2
Tôi chỉ nói rằng tính nguyên tử không đảm bảo an toàn cho luồng. Nếu bạn đủ thông minh để thiết kế cấu trúc dữ liệu hoặc thuật toán không có khóa, thì hãy tiếp tục. Nhưng bạn vẫn cần biết những đảm bảo mà trình biên dịch của bạn sẽ cung cấp cho bạn.
Eclipse

10

Nếu bạn muốn tăng nguyên tử trong C ++, bạn có thể sử dụng các thư viện C ++ 0x ( std::atomic kiểu dữ liệu) hoặc một cái gì đó như TBB.

Đã từng có lần hướng dẫn mã hóa GNU cho biết cập nhật các kiểu dữ liệu phù hợp với một từ là "thường an toàn" nhưng lời khuyên đó là sai đối với máy SMP, sai đối với một số kiến ​​trúc và sai khi sử dụng trình biên dịch tối ưu hóa.


Để làm rõ nhận xét "cập nhật loại dữ liệu một từ":

Có thể cho hai CPU trên một máy SMP ghi vào cùng một vị trí bộ nhớ trong cùng một chu kỳ và sau đó cố gắng truyền thay đổi cho các CPU khác và bộ nhớ cache. Ngay cả khi chỉ một từ dữ liệu đang được ghi, vì vậy việc ghi chỉ mất một chu kỳ để hoàn thành, chúng cũng xảy ra đồng thời nên bạn không thể đảm bảo lần ghi nào thành công. Bạn sẽ không nhận được dữ liệu được cập nhật một phần, nhưng một lần ghi sẽ biến mất vì không có cách nào khác để xử lý trường hợp này.

So sánh và hoán đổi tọa độ hợp lý giữa nhiều CPU, nhưng không có lý do gì để tin rằng mọi phép gán biến của các kiểu dữ liệu một từ sẽ sử dụng so sánh và hoán đổi.

Và trong khi trình biên dịch tối ưu hóa không ảnh hưởng đến cách biên dịch tải / lưu trữ, nó có thể thay đổi khi quá trình tải / lưu trữ xảy ra, gây ra sự cố nghiêm trọng nếu bạn mong đợi việc đọc và ghi của mình diễn ra theo đúng thứ tự xuất hiện trong mã nguồn ( nổi tiếng nhất là khóa được kiểm tra hai lần không hoạt động trong vanilla C ++).

LƯU Ý Câu trả lời ban đầu của tôi cũng nói rằng kiến ​​trúc 64 bit của Intel đã bị hỏng khi xử lý dữ liệu 64 bit. Điều đó không đúng, vì vậy tôi đã chỉnh sửa câu trả lời, nhưng bản chỉnh sửa của tôi cho rằng chip PowerPC đã bị hỏng. Điều đó đúng khi đọc các giá trị tức thời (tức là hằng số) vào thanh ghi (xem hai phần có tên "Đang tải con trỏ" trong danh sách 2 và danh sách 4). Nhưng có một hướng dẫn để tải dữ liệu từ bộ nhớ trong một chu kỳ ( lmw), vì vậy tôi đã xóa phần đó trong câu trả lời của mình.


Đọc và ghi là nguyên tử trên hầu hết các CPU hiện đại nếu dữ liệu của bạn được căn chỉnh tự nhiên và đúng kích thước, ngay cả với SMP và tối ưu hóa trình biên dịch. Tuy nhiên, có rất nhiều lưu ý, đặc biệt là với máy 64 bit, vì vậy có thể rất cồng kềnh để đảm bảo dữ liệu của bạn đáp ứng yêu cầu trên mọi máy.
Dan Olson

Cảm ơn đã cập nhật. Đúng, đọc và viết là nguyên tử vì bạn nói rằng chúng không thể hoàn thành một nửa, nhưng nhận xét của bạn nêu bật cách chúng tôi tiếp cận thực tế này trong thực tế. Tương tự với các rào cản bộ nhớ, chúng không ảnh hưởng đến bản chất nguyên tử của hoạt động, mà là cách chúng ta tiếp cận nó trong thực tế.
Dan Olson


4

Nếu ngôn ngữ lập trình của bạn không nói gì về các luồng nhưng lại chạy trên nền tảng đa luồng, thì làm cách nào để bất kỳ cấu trúc ngôn ngữ nào có thể an toàn cho luồng?

Như những người khác đã chỉ ra: bạn cần bảo vệ mọi quyền truy cập đa luồng vào các biến bằng các lệnh gọi nền tảng cụ thể.

Có những thư viện ngoài đó trừu tượng hóa tính cụ thể của nền tảng và tiêu chuẩn C ++ sắp tới đã điều chỉnh mô hình bộ nhớ của nó để đối phó với các luồng (và do đó có thể đảm bảo an toàn cho luồng).


4

Ngay cả khi nó được giảm xuống thành một lệnh hợp ngữ duy nhất, tăng giá trị trực tiếp trong bộ nhớ, nó vẫn không an toàn cho luồng.

Khi tăng một giá trị trong bộ nhớ, phần cứng thực hiện thao tác "đọc-sửa-ghi": nó đọc giá trị từ bộ nhớ, tăng giá trị và ghi lại vào bộ nhớ. Phần cứng x86 không có cách nào tăng trực tiếp trên bộ nhớ; RAM (và bộ nhớ đệm) chỉ có thể đọc và lưu trữ các giá trị, không sửa đổi chúng.

Bây giờ, giả sử bạn có hai lõi riêng biệt, trên các ổ cắm riêng biệt hoặc dùng chung một ổ cắm (có hoặc không có bộ nhớ cache dùng chung). Bộ xử lý đầu tiên đọc giá trị và trước khi nó có thể ghi lại giá trị đã cập nhật, bộ xử lý thứ hai sẽ đọc nó. Sau khi cả hai bộ xử lý ghi lại giá trị, nó sẽ chỉ được tăng lên một lần, không phải hai lần.

Có một cách để tránh vấn đề này; Bộ xử lý x86 (và hầu hết các bộ xử lý đa lõi mà bạn sẽ tìm thấy) có thể phát hiện loại xung đột này trong phần cứng và sắp xếp nó, để toàn bộ chuỗi đọc-sửa-ghi xuất hiện nguyên tử. Tuy nhiên, vì điều này rất tốn kém, nó chỉ được thực hiện khi được mã yêu cầu, trên x86 thường thông qua LOCKtiền tố. Các kiến ​​trúc khác có thể làm điều này theo những cách khác, với kết quả tương tự; ví dụ: liên kết tải / có điều kiện lưu trữ và so sánh và hoán đổi nguyên tử (bộ xử lý x86 gần đây cũng có bộ xử lý cuối cùng này).

Lưu ý rằng việc sử dụng volatilekhông giúp ích gì ở đây; nó chỉ cho trình biên dịch biết rằng biến có thể đã được sửa đổi bên ngoài và việc đọc biến đó không được lưu vào bộ nhớ đệm trong một thanh ghi hoặc được tối ưu hóa. Nó không làm cho trình biên dịch sử dụng các nguyên tố nguyên tử.

Cách tốt nhất là sử dụng nguyên tử nguyên tử (nếu trình biên dịch hoặc thư viện của bạn có chúng), hoặc thực hiện gia tăng trực tiếp trong hợp ngữ (sử dụng hướng dẫn nguyên tử chính xác).


2

Đừng bao giờ giả định rằng một gia số sẽ biên dịch xuống một hoạt động nguyên tử. Sử dụng InterlockedIncrement hoặc bất kỳ chức năng tương tự nào tồn tại trên nền tảng mục tiêu của bạn.

Chỉnh sửa: Tôi vừa tra cứu câu hỏi cụ thể này và gia số trên X86 là nguyên tử trên các hệ thống bộ xử lý đơn lẻ, nhưng không phải trên hệ thống đa xử lý. Sử dụng tiền tố khóa có thể làm cho nó trở thành nguyên tử, nhưng nó dễ di động hơn nhiều chỉ để sử dụng InterlockedIncrement.


1
InterlockedIncrement () là một hàm Windows; tất cả các hộp Linux và các máy OS X hiện đại của tôi đều dựa trên x64, vì vậy việc nói InterlockedIncrement () là 'di động hơn nhiều' so với mã x86 là khá giả.
Pete Kirkham

Nó di động hơn nhiều theo nghĩa là C di động hơn nhiều so với lắp ráp. Mục tiêu ở đây là giúp bạn không phải dựa vào lắp ráp được tạo cụ thể cho một bộ xử lý cụ thể. Nếu các hệ điều hành khác là mối quan tâm của bạn thì InterlockedIncrement dễ dàng được bao bọc.
Dan Olson

2

Theo bài học lắp ráp này trên x86, bạn có thể thêm một thanh ghi vào vị trí bộ nhớ , vì vậy có khả năng mã của bạn có thể thực thi nguyên tử '++ i' ou 'i ++'. Nhưng như đã nói trong một bài đăng khác, C ansi không áp dụng tính nguyên tử cho opération '++', vì vậy bạn không thể chắc chắn về những gì trình biên dịch của bạn sẽ tạo ra.


1

Tiêu chuẩn C ++ 1998 không có gì để nói về các luồng, mặc dù tiêu chuẩn tiếp theo (sẽ có hiệu lực trong năm nay hoặc năm sau). Do đó, bạn không thể nói bất cứ điều gì thông minh về sự an toàn của các hoạt động của luồng mà không đề cập đến việc triển khai. Nó không chỉ là bộ xử lý đang được sử dụng mà còn là sự kết hợp của trình biên dịch, hệ điều hành và mô hình luồng.

Trong trường hợp không có tài liệu ngược lại, tôi sẽ không cho rằng bất kỳ hành động nào là an toàn theo luồng, đặc biệt là với bộ xử lý đa lõi (hoặc hệ thống đa xử lý). Tôi cũng không tin tưởng các bài kiểm tra, vì các vấn đề đồng bộ hóa luồng có thể chỉ xảy ra một cách tình cờ.

Không có gì là an toàn cho luồng trừ khi bạn có tài liệu cho biết nó dành cho hệ thống cụ thể mà bạn đang sử dụng.


1

Ném i vào bộ nhớ cục bộ của luồng; nó không phải là nguyên tử, nhưng nó không quan trọng.


1

AFAIK, Theo tiêu chuẩn C ++, đọc / ghi tới an intlà nguyên tử.

Tuy nhiên, tất cả những gì điều này làm là loại bỏ hành vi không xác định liên quan đến một cuộc chạy đua dữ liệu.

Nhưng vẫn sẽ có một cuộc chạy đua dữ liệu nếu cả hai luồng cố gắng tăng lên i.

Hãy tưởng tượng tình huống sau:

i = 0Ban đầu hãy :

Luồng A đọc giá trị từ bộ nhớ và lưu trữ trong bộ nhớ cache của chính nó. Chủ đề A tăng giá trị lên 1.

Luồng B đọc giá trị từ bộ nhớ và lưu trữ trong bộ nhớ cache của chính nó. Chủ đề B tăng giá trị lên 1.

Nếu đây là tất cả một chuỗi duy nhất bạn sẽ nhận được i = 2trong bộ nhớ.

Nhưng với cả hai luồng, mỗi luồng sẽ ghi các thay đổi của nó và do đó Luồng A ghi i = 1lại vào bộ nhớ, và Luồng B ghi i = 1vào bộ nhớ.

Nó được xác định rõ ràng, không có sự phá hủy hoặc xây dựng từng phần hay bất kỳ loại xé rách nào của một vật thể, nhưng nó vẫn là một cuộc đua dữ liệu.

Để tăng nguyên tử, ibạn có thể sử dụng:

std::atomic<int>::fetch_add(1, std::memory_order_relaxed)

Thứ tự thoải mái có thể được sử dụng bởi vì chúng tôi không quan tâm nơi hoạt động này diễn ra, tất cả những gì chúng tôi quan tâm là hoạt động gia tăng là nguyên tử.


0

Bạn nói "đó chỉ là một hướng dẫn, nó sẽ không bị gián đoạn bởi một công tắc ngữ cảnh." - Đó là tất cả và tốt cho một CPU đơn, nhưng còn một CPU lõi kép thì sao? Sau đó, bạn thực sự có thể có hai luồng truy cập cùng một biến cùng một lúc mà không cần bất kỳ công tắc ngữ cảnh nào.

Nếu không biết ngôn ngữ, câu trả lời là kiểm tra khả năng của nó.


4
Bạn không tìm ra thứ gì đó có an toàn cho luồng hay không bằng cách kiểm tra nó - các vấn đề về luồng có thể là một trong một triệu lần xuất hiện. Bạn tra cứu nó trong tài liệu của mình. Nếu nó không được đảm bảo an toàn luồng theo tài liệu của bạn, thì không.
Nhật thực

2
Đồng ý với @Josh ở đây. Một cái gì đó chỉ an toàn theo chuỗi nếu nó có thể được chứng minh về mặt toán học thông qua phân tích mã cơ bản. Không có số lượng thử nghiệm nào có thể bắt đầu tiếp cận điều đó.
Rex M

Đó là một câu trả lời tuyệt vời cho đến câu cuối cùng.
Rob K

0

Tôi nghĩ rằng nếu biểu thức "i ++" là duy nhất trong một câu lệnh, thì nó tương đương với "++ i", trình biên dịch đủ thông minh để không giữ một giá trị tạm thời, v.v. Vì vậy, nếu bạn có thể sử dụng chúng thay thế cho nhau (nếu không thì bạn đã thắng Không phải hỏi bạn sử dụng cái nào), không quan trọng bạn sử dụng cái nào vì chúng gần như giống nhau (ngoại trừ tính thẩm mỹ).

Dù sao, ngay cả khi toán tử tăng là nguyên tử, điều đó không đảm bảo rằng phần còn lại của tính toán sẽ nhất quán nếu bạn không sử dụng các khóa chính xác.

Nếu bạn muốn tự mình thử nghiệm, hãy viết một chương trình trong đó N luồng tăng đồng thời một biến chia sẻ M lần mỗi ... nếu giá trị nhỏ hơn N * M, thì một số gia tăng đã bị ghi đè. Hãy thử nó với cả preincrement và postincrement và cho chúng tôi biết ;-)


0

Đối với bộ đếm, tôi khuyên bạn nên sử dụng thành ngữ so sánh và hoán đổi, vừa không khóa vừa an toàn cho luồng.

Đây là bằng Java:

public class IntCompareAndSwap {
    private int value = 0;

    public synchronized int get(){return value;}

    public synchronized int compareAndSwap(int p_expectedValue, int p_newValue){
        int oldValue = value;

        if (oldValue == p_expectedValue)
            value = p_newValue;

        return oldValue;
    }
}

public class IntCASCounter {

    public IntCASCounter(){
        m_value = new IntCompareAndSwap();
    }

    private IntCompareAndSwap m_value;

    public int getValue(){return m_value.get();}

    public void increment(){
        int temp;
        do {
            temp = m_value.get();
        } while (temp != m_value.compareAndSwap(temp, temp + 1));

    }

    public void decrement(){
        int temp;
        do {
            temp = m_value.get();
        } while (temp > 0 && temp != m_value.compareAndSwap(temp, temp - 1));

    }
}

Có vẻ giống với hàm test_and_set.
samoz

1
Bạn đã viết "không khóa", nhưng "đồng bộ hóa" không có nghĩa là khóa?
Corey Trager
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.