Một điều kiện cuộc đua là gì?


982

Khi viết các ứng dụng đa luồng, một trong những vấn đề phổ biến nhất gặp phải là tình trạng chủng tộc.

Câu hỏi của tôi cho cộng đồng là:

Điều kiện cuộc đua là gì?
Làm thế nào để bạn phát hiện ra chúng?
Làm thế nào để bạn xử lý chúng?
Cuối cùng, làm thế nào để bạn ngăn chặn chúng xảy ra?


3
Có một chương tuyệt vời trong Lập trình bảo mật cho Linux HOWTO mô tả chúng là gì và cách tránh chúng.
Craig H

4
Tôi muốn đề cập đến điều đó - mà không chỉ định ngôn ngữ - hầu hết các phần của câu hỏi này không thể được trả lời đúng, bởi vì trong các ngôn ngữ khác nhau, định nghĩa, hậu quả và các công cụ để ngăn chặn chúng có thể khác nhau.
MikeMB

@MikeMB. Đồng ý, ngoại trừ khi phân tích thực thi mã byte, giống như được thực hiện bởi Race Catch (xem chủ đề này stackoverflow.com/a/29361427/1363844 ) chúng tôi có thể giải quyết tất cả khoảng 62 ngôn ngữ biên dịch thành mã byte (xem en.wikipedia.org / wiki / List_of_JVM_lacular )
Ben

Câu trả lời:


1238

Một điều kiện cuộc đua xảy ra khi hai hoặc nhiều luồng có thể truy cập dữ liệu được chia sẻ và họ cố gắng thay đổi nó cùng một lúc. Vì thuật toán lập lịch luồng có thể trao đổi giữa các luồng bất cứ lúc nào, bạn không biết thứ tự các luồng sẽ cố gắng truy cập dữ liệu được chia sẻ. Do đó, kết quả của sự thay đổi dữ liệu phụ thuộc vào thuật toán lập lịch luồng, tức là cả hai luồng đều "chạy đua" để truy cập / thay đổi dữ liệu.

Sự cố thường xảy ra khi một luồng thực hiện "kiểm tra sau đó hành động" (ví dụ: "kiểm tra" nếu giá trị là X, sau đó "hành động" để làm một việc gì đó phụ thuộc vào giá trị là X) và một luồng khác thực hiện điều đó với giá trị trong giữa "kiểm tra" và "hành động". Ví dụ:

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

Vấn đề là, y có thể là 10 hoặc có thể là bất cứ điều gì, tùy thuộc vào việc một luồng khác có thay đổi x ở giữa kiểm tra và hành động hay không. Bạn không có cách nào để biết

Để ngăn điều kiện cuộc đua xảy ra, bạn thường sẽ khóa một khóa xung quanh dữ liệu được chia sẻ để đảm bảo chỉ có một luồng có thể truy cập dữ liệu tại một thời điểm. Điều này có nghĩa là một cái gì đó như thế này:

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x

121
Các chủ đề khác làm gì khi gặp khóa? Nó có chờ không? Lỗi?
Brian Ortiz

174
Có, các luồng khác sẽ phải đợi cho đến khi khóa được phát hành trước khi nó có thể tiến hành. Điều này làm cho nó rất quan trọng rằng khóa được giải phóng bởi luồng giữ khi nó được hoàn thành với nó. Nếu nó không bao giờ phát hành nó, thì các chủ đề khác sẽ chờ đợi vô thời hạn.
Lehane

2
@Ian Trong một hệ thống đa luồng sẽ luôn có những lúc tài nguyên cần được chia sẻ. Để nói rằng một cách tiếp cận là xấu mà không đưa ra một giải pháp thay thế chỉ là không hiệu quả. Tôi luôn tìm cách cải thiện và nếu có một giải pháp thay thế, tôi sẽ sẵn sàng nghiên cứu và cân nhắc các ưu và nhược điểm.
Despertar

2
@Despertar ... cũng vậy, không nhất thiết là tài nguyên sẽ luôn cần được chia sẻ trong một hệ thống phân luồng. Ví dụ, bạn có thể có một mảng trong đó mỗi phần tử cần xử lý. Bạn có thể phân vùng mảng và có một luồng cho mỗi phân vùng và các luồng có thể thực hiện công việc của chúng hoàn toàn độc lập với nhau.
Ian Warburton

12
Để một cuộc đua xảy ra, đủ một luồng cố gắng thay đổi dữ liệu được chia sẻ trong khi các luồng còn lại có thể đọc hoặc thay đổi nó.
SomeWittyUsername

213

"Điều kiện chủng tộc" tồn tại khi mã đa luồng (hoặc nói cách khác là song song) sẽ truy cập vào tài nguyên được chia sẻ có thể làm như vậy để gây ra kết quả không mong muốn.

Lấy ví dụ này:

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

Nếu bạn có 5 luồng thực thi mã này cùng một lúc, giá trị của x KHÔNG NÊN kết thúc là 50.000.000. Thực tế nó sẽ thay đổi theo từng lần chạy.

Điều này là do, để mỗi luồng tăng giá trị của x, họ phải làm như sau: (đơn giản hóa, rõ ràng)

Lấy giá trị của x
Thêm 1 vào giá trị này
Lưu giá trị này vào x

Bất kỳ luồng nào cũng có thể ở bất kỳ bước nào trong quy trình này bất cứ lúc nào và chúng có thể bước lên nhau khi có tài nguyên chia sẻ. Trạng thái của x có thể được thay đổi bởi một luồng khác trong thời gian giữa x đang được đọc và khi nó được viết lại.

Giả sử một luồng lấy giá trị của x, nhưng chưa lưu trữ nó. Một luồng khác cũng có thể truy xuất cùng một giá trị của x (vì chưa có luồng nào thay đổi nó) và sau đó cả hai sẽ lưu trữ cùng một giá trị (x + 1) trong x!

Thí dụ:

Chủ đề 1: đọc x, giá trị là 7
Chủ đề 1: thêm 1 vào x, giá trị bây giờ là 8
Chủ đề 2: đọc x, giá trị là 7
Chủ đề 1: lưu trữ 8 trong x
Chủ đề 2: thêm 1 vào x, giá trị hiện là 8
Chủ đề 2: lưu trữ 8 trong x

Điều kiện cuộc đua có thể tránh được bằng cách sử dụng một số loại cơ chế khóa trước khi mã truy cập vào tài nguyên được chia sẻ:

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

Ở đây, câu trả lời được đưa ra là 50.000.000 mỗi lần.

Để biết thêm về khóa, tìm kiếm: mutex, semaphore, phần quan trọng, tài nguyên được chia sẻ.


Xem jakob.engbloms.se/archives/65 để biết ví dụ về chương trình kiểm tra xem những thứ đó có tệ đến mức nào không ... nó thực sự phụ thuộc vào mô hình bộ nhớ của máy bạn đang chạy.
jakobengblom2

1
Làm thế nào nó có thể nhận được đến 50 triệu nếu nó phải dừng lại ở mức 10 triệu?

9
@nocomprende: Bởi 5 luồng thực thi cùng một mã tại một thời điểm, như được mô tả ngay bên dưới đoạn trích ...
Jon Skeet

4
@JonSkeet Bạn nói đúng, tôi nhầm lẫn i và x. Cảm ơn bạn.

Khóa kiểm tra kép trong việc triển khai mẫu Singleton là một ví dụ về việc ngăn chặn tình trạng chủng tộc.
Bharat Dodeja

150

Điều kiện cuộc đua là gì?

Bạn đang lên kế hoạch đi xem phim lúc 5 giờ chiều. Bạn hỏi về sự sẵn có của vé lúc 4 giờ chiều. Các đại diện nói rằng họ có sẵn. Bạn thư giãn và đến cửa sổ vé 5 phút trước khi chương trình diễn ra. Tôi chắc rằng bạn có thể đoán những gì xảy ra: đó là một ngôi nhà đầy đủ. Vấn đề ở đây là trong khoảng thời gian giữa kiểm tra và hành động. Bạn hỏi lúc 4 và hành động lúc 5. Trong lúc đó, một người khác đã lấy vé. Đó là một điều kiện cuộc đua - cụ thể là kịch bản "kiểm tra hành động" về điều kiện cuộc đua.

Làm thế nào để bạn phát hiện ra chúng?

Xem xét mã tôn giáo, kiểm tra đơn vị đa luồng. Không có phím tắt. Có một số plugin Eclipse nổi lên về điều này, nhưng chưa có gì ổn định.

Làm thế nào để bạn xử lý và ngăn chặn chúng?

Điều tốt nhất sẽ là tạo ra các chức năng không trạng thái và không trạng thái, sử dụng bất biến càng nhiều càng tốt. Nhưng điều đó không phải lúc nào cũng có thể. Vì vậy, sử dụng java.util.concản.atomic, cấu trúc dữ liệu đồng thời, đồng bộ hóa phù hợp và đồng thời dựa trên diễn viên sẽ giúp ích.

Tài nguyên tốt nhất cho sự tương tranh là JCIP. Bạn cũng có thể nhận được một số chi tiết về giải thích ở trên .


Đánh giá mã và kiểm tra đơn vị là thứ yếu để mô hình hóa dòng chảy giữa hai tai của bạn và sử dụng ít bộ nhớ dùng chung hơn.
Acumenus

2
Tôi đánh giá cao ví dụ thực tế về tình trạng chủng tộc
Tom O.

11
Giống như câu trả lời ngón tay cái lên . Giải pháp là: bạn khóa các vé giữa 4-5 với mutex (ngoại lệ lẫn nhau, c ++). Trong thế giới thực, nó được gọi là đặt vé :)
Volt

1
sẽ là một câu trả lời hợp lý nếu bạn bỏ các bit chỉ có java (câu hỏi không phải là về Java, mà là các điều kiện chủng tộc nói chung)
Corey Goldberg

Không. Đây không phải là một điều kiện cuộc đua. Từ góc độ "kinh doanh", bạn chỉ chờ đợi quá lâu. Rõ ràng backorder không phải là một giải pháp. Hãy thử một công cụ mở rộng nếu không chỉ cần mua vé dưới dạng bảo hiểm
csherriff

65

Có một sự khác biệt kỹ thuật quan trọng giữa điều kiện cuộc đua và cuộc đua dữ liệu. Hầu hết các câu trả lời dường như đưa ra giả định rằng các thuật ngữ này là tương đương, nhưng chúng không phải là.

Cuộc đua dữ liệu xảy ra khi 2 hướng dẫn truy cập vào cùng một vị trí bộ nhớ, ít nhất một trong số các truy cập này là ghi và không có gì xảy ra trước khi đặt hàng trong số các truy cập này. Bây giờ những gì cấu thành một sự kiện xảy ra trước khi đặt hàng là đối tượng của rất nhiều cuộc tranh luận, nhưng nói chung, các cặp khóa-khóa trên cùng một biến khóa và các cặp tín hiệu chờ trên cùng một biến điều kiện tạo ra một lệnh xảy ra trước khi xảy ra.

Một điều kiện cuộc đua là một lỗi ngữ nghĩa. Đó là một lỗ hổng xảy ra trong thời gian hoặc thứ tự các sự kiện dẫn đến hành vi chương trình sai lầm .

Nhiều điều kiện chủng tộc có thể (và trên thực tế là) gây ra bởi các cuộc đua dữ liệu, nhưng điều này là không cần thiết. Trên thực tế, các cuộc đua dữ liệu và điều kiện chủng tộc không phải là điều cần thiết, cũng không phải là điều kiện đủ cho nhau. Bài đăng trên blog này cũng giải thích sự khác biệt rất tốt, với một ví dụ giao dịch ngân hàng đơn giản. Dưới đây là một ví dụ đơn giản giải thích sự khác biệt.

Bây giờ chúng tôi đóng đinh các thuật ngữ, chúng ta hãy cố gắng trả lời câu hỏi ban đầu.

Cho rằng điều kiện chủng tộc là lỗi ngữ nghĩa, không có cách nào chung để phát hiện ra chúng. Điều này là do không có cách nào có một nhà tiên tri tự động có thể phân biệt hành vi chương trình chính xác và không chính xác trong trường hợp chung. Phát hiện chủng tộc là một vấn đề không thể giải quyết được.

Mặt khác, các cuộc đua dữ liệu có một định nghĩa chính xác không nhất thiết liên quan đến tính chính xác, và do đó người ta có thể phát hiện ra chúng. Có nhiều hương vị của trình phát hiện cuộc đua dữ liệu (phát hiện cuộc đua dữ liệu tĩnh / động, phát hiện cuộc đua dữ liệu dựa trên khóa, phát hiện cuộc đua dữ liệu dựa trên trước, phát hiện cuộc đua dữ liệu lai). Một trình phát hiện cuộc đua dữ liệu động hiện đại là ThreadSanitizer hoạt động rất tốt trong thực tế.

Xử lý các cuộc đua dữ liệu nói chung đòi hỏi một số kỷ luật lập trình để tạo ra các cạnh xảy ra - trước khi các cạnh truy cập vào dữ liệu được chia sẻ (trong khi phát triển hoặc một khi chúng được phát hiện bằng các công cụ được đề cập ở trên). điều này có thể được thực hiện thông qua các khóa, biến điều kiện, semaphores, v.v. Tuy nhiên, người ta cũng có thể sử dụng các mô hình lập trình khác nhau như truyền tin nhắn (thay vì bộ nhớ dùng chung) để tránh các cuộc đua dữ liệu khi xây dựng.


Sự khác biệt là rất quan trọng để hiểu điều kiện chủng tộc. Cảm ơn!
Chương trìnhCpp

37

Một định nghĩa sắp xếp chính tắc là " khi hai luồng truy cập cùng một vị trí trong bộ nhớ cùng một lúc và ít nhất một trong số các truy cập đó là ghi ". Trong trường hợp, chủ đề "người đọc" có thể nhận được giá trị cũ hoặc giá trị mới, tùy thuộc vào chủ đề nào "chiến thắng cuộc đua". Trên thực tế, đây không phải là một lỗi bug, một số thuật toán cấp thấp thực sự có lông thực hiện điều này trên mục đích, nhưng nói chung nên tránh. @Steve Gury là một ví dụ điển hình khi nó có thể là một vấn đề.


3
Bạn có thể vui lòng cho một ví dụ về làm thế nào điều kiện cuộc đua có thể hữu ích? Googling đã không giúp đỡ.
Alex V.

3
@Alex V. Tại thời điểm này, tôi không biết tôi đang nói về cái gì. Tôi nghĩ rằng điều này có thể là một tài liệu tham khảo về lập trình không khóa, nhưng nó không thực sự chính xác để nói rằng điều đó phụ thuộc vào điều kiện chủng tộc.
Chris Conway

33

Một điều kiện chủng tộc là một loại lỗi, chỉ xảy ra với một số điều kiện thời gian nhất định.

Ví dụ: Hãy tưởng tượng bạn có hai luồng, A và B.

Trong chủ đề A:

if( object.a != 0 )
    object.avg = total / object.a

Trong chủ đề B:

object.a = 0

Nếu luồng A được ưu tiên ngay sau khi kiểm tra đối tượng đó. Không phải là null, B sẽ làm a = 0 và khi luồng A sẽ thu được bộ xử lý, nó sẽ thực hiện "chia cho 0".

Lỗi này chỉ xảy ra khi luồng A được xử lý ngay sau câu lệnh if, nó rất hiếm, nhưng nó có thể xảy ra.


21

Điều kiện cuộc đua không chỉ liên quan đến phần mềm mà còn liên quan đến phần cứng. Trên thực tế, thuật ngữ ban đầu được đặt ra bởi ngành công nghiệp phần cứng.

Theo wikipedia :

Các bắt nguồn hạn với ý tưởng của hai tín hiệu đua nhau để ảnh hưởng đến sản lượng đầu tiên .

Điều kiện cuộc đua trong một mạch logic:

nhập mô tả hình ảnh ở đây

Công nghiệp phần mềm lấy thuật ngữ này mà không sửa đổi, điều này làm cho nó hơi khó hiểu.

Bạn cần thực hiện một số thay thế để ánh xạ nó tới thế giới phần mềm:

  • "hai tín hiệu" => "hai luồng" / "hai tiến trình"
  • "ảnh hưởng đến đầu ra" => "ảnh hưởng đến một số trạng thái chia sẻ"

Vì vậy, điều kiện chủng tộc trong ngành công nghiệp phần mềm có nghĩa là "hai luồng" / "hai tiến trình" đua nhau để "ảnh hưởng đến một số trạng thái chia sẻ" và kết quả cuối cùng của trạng thái chia sẻ sẽ phụ thuộc vào một số khác biệt về thời gian, có thể do một số trường hợp cụ thể gây ra thứ tự khởi động quá trình, lập lịch trình / luồng, v.v.


20

Một điều kiện cuộc đua là một tình huống về lập trình đồng thời trong đó hai luồng hoặc quy trình đồng thời cạnh tranh cho một tài nguyên và trạng thái cuối cùng kết quả phụ thuộc vào người lấy tài nguyên trước.


chỉ rực rỡ giải thích
gokareless

Trạng thái cuối cùng của cái gì?
La Mã Alexandrovich

1
@RomanAlexandrovich Trạng thái cuối cùng của chương trình. Trạng thái đề cập đến những thứ như giá trị của các biến, v.v ... Xem câu trả lời xuất sắc của Lehane. "Trạng thái" trong ví dụ của anh ta sẽ đề cập đến các giá trị cuối cùng của 'x' và 'y'.
AMTerp

19

Điều kiện cuộc đua xảy ra trong các ứng dụng đa luồng hoặc hệ thống đa quy trình. Một điều kiện chủng tộc, ở mức cơ bản nhất, là bất cứ điều gì đưa ra giả định rằng hai điều không cùng một luồng hoặc quá trình sẽ xảy ra theo một thứ tự cụ thể, mà không thực hiện các bước để đảm bảo rằng chúng thực hiện. Điều này xảy ra phổ biến khi hai luồng đang truyền tin nhắn bằng cách đặt và kiểm tra các biến thành viên của một lớp cả hai có thể truy cập. Hầu như luôn luôn có một điều kiện cuộc đua khi một luồng gọi giấc ngủ để cho một luồng thời gian khác hoàn thành một nhiệm vụ (trừ khi giấc ngủ đó ở trong một vòng lặp, với một số cơ chế kiểm tra).

Các công cụ để ngăn chặn các điều kiện chủng tộc phụ thuộc vào ngôn ngữ và HĐH, nhưng một số công cụ comon là các trường hợp đột biến, các phần quan trọng và tín hiệu. Mutexes là tốt khi bạn muốn chắc chắn rằng bạn là người duy nhất làm điều gì đó. Tín hiệu là tốt khi bạn muốn chắc chắn rằng người khác đã hoàn thành việc gì đó. Giảm thiểu các tài nguyên được chia sẻ cũng có thể giúp ngăn chặn các hành vi không mong muốn

Phát hiện các điều kiện chủng tộc có thể khó khăn, nhưng có một vài dấu hiệu. Mã dựa nhiều vào giấc ngủ dễ bị điều kiện chủng tộc, vì vậy trước tiên hãy kiểm tra các cuộc gọi để ngủ trong mã bị ảnh hưởng. Thêm giấc ngủ đặc biệt dài cũng có thể được sử dụng để gỡ lỗi để thử và buộc một thứ tự cụ thể của các sự kiện. Điều này có thể hữu ích để tái tạo hành vi, xem liệu bạn có thể làm cho nó biến mất bằng cách thay đổi thời gian của sự vật và để đưa ra các giải pháp thử nghiệm. Các giấc ngủ nên được loại bỏ sau khi gỡ lỗi.

Dấu hiệu chữ ký cho thấy một người có tình trạng chủng tộc, là nếu có một vấn đề chỉ xảy ra không liên tục trên một số máy. Các lỗi thông thường sẽ là sự cố và bế tắc. Với việc đăng nhập, bạn sẽ có thể tìm thấy khu vực bị ảnh hưởng và làm việc trở lại từ đó.


10

Microsoft thực sự đã xuất bản một bài viết thực sự chi tiết về vấn đề điều kiện chủng tộc và bế tắc. Bản tóm tắt được tóm tắt nhiều nhất từ ​​nó sẽ là đoạn tiêu đề:

Một điều kiện cuộc đua xảy ra khi hai luồng truy cập vào một biến được chia sẻ cùng một lúc. Chuỗi đầu tiên đọc biến và luồng thứ hai đọc cùng giá trị từ biến. Sau đó, luồng đầu tiên và luồng thứ hai thực hiện các hoạt động của chúng trên giá trị và chúng chạy đua để xem luồng nào có thể ghi giá trị cuối cùng vào biến được chia sẻ. Giá trị của luồng ghi giá trị cuối cùng của nó được giữ nguyên, bởi vì luồng đang ghi trên giá trị mà luồng trước đó đã viết.


5

Một điều kiện cuộc đua là gì?

Tình huống khi quá trình phụ thuộc rất nhiều vào trình tự hoặc thời gian của các sự kiện khác.

Ví dụ, cả Bộ xử lý A và bộ xử lý B đều cần tài nguyên giống hệt nhau để thực thi.

Làm thế nào để bạn phát hiện ra chúng?

Có các công cụ để tự động phát hiện tình trạng cuộc đua:

Làm thế nào để bạn xử lý chúng?

Điều kiện cuộc đua có thể được xử lý bởi Mutex hoặc Semaphores . Chúng hoạt động như một khóa cho phép một quá trình có được tài nguyên dựa trên các yêu cầu nhất định để ngăn chặn tình trạng chủng tộc.

Làm thế nào để bạn ngăn chặn chúng xảy ra?

Có nhiều cách khác nhau để ngăn chặn tình trạng chủng tộc, chẳng hạn như Tránh Phần quan trọng .

  1. Không có hai quá trình đồng thời bên trong các khu vực quan trọng của họ. ( Loại trừ lẫn nhau)
  2. Không có giả định nào được thực hiện về tốc độ hoặc số lượng CPU.
  3. Không có quá trình chạy bên ngoài khu vực quan trọng của nó mà chặn các quá trình khác.
  4. Không có quá trình phải chờ mãi để vào khu vực quan trọng của nó. (A chờ tài nguyên B, B chờ tài nguyên C, C chờ tài nguyên A)

2

Tình trạng cuộc đua là tình huống không mong muốn xảy ra khi một thiết bị hoặc hệ thống cố gắng thực hiện hai hoặc nhiều hoạt động cùng một lúc, nhưng vì bản chất của thiết bị hoặc hệ thống, các hoạt động phải được thực hiện theo trình tự phù hợp để được thực hiện đúng

Trong bộ nhớ hoặc bộ nhớ máy tính, tình trạng cuộc đua có thể xảy ra nếu các lệnh đọc và ghi một lượng lớn dữ liệu được nhận gần như cùng một lúc và máy cố ghi đè lên một số hoặc tất cả dữ liệu cũ trong khi dữ liệu cũ vẫn còn đọc. Kết quả có thể là một hoặc nhiều trường hợp sau: sự cố máy tính, thông báo "hoạt động bất hợp pháp" và tắt chương trình, lỗi đọc dữ liệu cũ hoặc lỗi ghi dữ liệu mới.


2

Dưới đây là ví dụ về Số dư tài khoản ngân hàng cổ điển sẽ giúp người mới hiểu Chủ đề trong Java dễ dàng ghi lại các điều kiện cuộc đua:

public class BankAccount {

/**
 * @param args
 */
int accountNumber;
double accountBalance;

public synchronized boolean Deposit(double amount){
    double newAccountBalance=0;
    if(amount<=0){
        return false;
    }
    else {
        newAccountBalance = accountBalance+amount;
        accountBalance=newAccountBalance;
        return true;
    }

}
public synchronized boolean Withdraw(double amount){
    double newAccountBalance=0;
    if(amount>accountBalance){
        return false;
    }
    else{
        newAccountBalance = accountBalance-amount;
        accountBalance=newAccountBalance;
        return true;
    }
}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    BankAccount b = new BankAccount();
    b.accountBalance=2000;
    System.out.println(b.Withdraw(3000));

}

1

Bạn có thể ngăn chặn tình trạng chủng tộc , nếu bạn sử dụng các lớp "Nguyên tử". Lý do chỉ là các chủ đề không tách biệt hoạt động get và set, ví dụ như sau:

AtomicInteger ai = new AtomicInteger(2);
ai.getAndAdd(5);

Kết quả là bạn sẽ có 7 liên kết "ai". Mặc dù bạn đã thực hiện hai hành động, nhưng cả hai thao tác đều xác nhận cùng một luồng và không có luồng nào khác can thiệp vào điều này, điều đó có nghĩa là không có điều kiện cuộc đua!


0

Hãy thử ví dụ cơ bản này để hiểu rõ hơn về tình trạng chủng tộc:

    public class ThreadRaceCondition {

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Account myAccount = new Account(22222222);

        // Expected deposit: 250
        for (int i = 0; i < 50; i++) {
            Transaction t = new Transaction(myAccount,
                    Transaction.TransactionType.DEPOSIT, 5.00);
            t.start();
        }

        // Expected withdrawal: 50
        for (int i = 0; i < 50; i++) {
            Transaction t = new Transaction(myAccount,
                    Transaction.TransactionType.WITHDRAW, 1.00);
            t.start();

        }

        // Temporary sleep to ensure all threads are completed. Don't use in
        // realworld :-)
        Thread.sleep(1000);
        // Expected account balance is 200
        System.out.println("Final Account Balance: "
                + myAccount.getAccountBalance());

    }

}

class Transaction extends Thread {

    public static enum TransactionType {
        DEPOSIT(1), WITHDRAW(2);

        private int value;

        private TransactionType(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    };

    private TransactionType transactionType;
    private Account account;
    private double amount;

    /*
     * If transactionType == 1, deposit else if transactionType == 2 withdraw
     */
    public Transaction(Account account, TransactionType transactionType,
            double amount) {
        this.transactionType = transactionType;
        this.account = account;
        this.amount = amount;
    }

    public void run() {
        switch (this.transactionType) {
        case DEPOSIT:
            deposit();
            printBalance();
            break;
        case WITHDRAW:
            withdraw();
            printBalance();
            break;
        default:
            System.out.println("NOT A VALID TRANSACTION");
        }
        ;
    }

    public void deposit() {
        this.account.deposit(this.amount);
    }

    public void withdraw() {
        this.account.withdraw(amount);
    }

    public void printBalance() {
        System.out.println(Thread.currentThread().getName()
                + " : TransactionType: " + this.transactionType + ", Amount: "
                + this.amount);
        System.out.println("Account Balance: "
                + this.account.getAccountBalance());
    }
}

class Account {
    private int accountNumber;
    private double accountBalance;

    public int getAccountNumber() {
        return accountNumber;
    }

    public double getAccountBalance() {
        return accountBalance;
    }

    public Account(int accountNumber) {
        this.accountNumber = accountNumber;
    }

    // If this method is not synchronized, you will see race condition on
    // Remove syncronized keyword to see race condition
    public synchronized boolean deposit(double amount) {
        if (amount < 0) {
            return false;
        } else {
            accountBalance = accountBalance + amount;
            return true;
        }
    }

    // If this method is not synchronized, you will see race condition on
    // Remove syncronized keyword to see race condition
    public synchronized boolean withdraw(double amount) {
        if (amount > accountBalance) {
            return false;
        } else {
            accountBalance = accountBalance - amount;
            return true;
        }
    }
}

0

Bạn không luôn muốn loại bỏ một điều kiện cuộc đua. Nếu bạn có một cờ có thể được đọc và viết bởi nhiều luồng và cờ này được đặt thành 'xong' bởi một luồng để luồng khác dừng xử lý khi cờ được đặt thành 'xong', bạn không muốn "chạy đua" điều kiện "để được loại bỏ. Trong thực tế, điều này có thể được gọi là một điều kiện chủng tộc lành tính.

Tuy nhiên, bằng cách sử dụng một công cụ để phát hiện tình trạng chủng tộc, nó sẽ được phát hiện là một điều kiện cuộc đua có hại.

Chi tiết hơn về điều kiện cuộc đua ở đây, http://msdn.microsoft.com/en-us/magazine/cc546569.aspx .


Ngôn ngữ nào là câu trả lời của bạn dựa trên?
MikeMB

Thẳng thắn mà nói có vẻ như với tôi rằng nếu bạn có điều kiện chủng tộc cho mỗi gia nhập , bạn không architecting mã của bạn một cách kiểm soát chặt chẽ. Mà, trong khi nó có thể không phải là một vấn đề trong trường hợp lý thuyết của bạn, là bằng chứng của những vấn đề lớn hơn với cách bạn thiết kế và phát triển phần mềm. Mong đợi để đối mặt với lỗi tình trạng chủng tộc đau đớn sớm hay muộn.
Kỹ sư

0

Hãy xem xét một thao tác phải hiển thị số đếm ngay khi số đếm được tăng lên. tức là, ngay khi CounterThread tăng giá trị DisplayThread cần hiển thị giá trị được cập nhật gần đây.

int i = 0;

Đầu ra

CounterThread -> i = 1  
DisplayThread -> i = 1  
CounterThread -> i = 2  
CounterThread -> i = 3  
CounterThread -> i = 4  
DisplayThread -> i = 4

Tại đây CounterThread nhận được khóa thường xuyên và cập nhật giá trị trước khi DisplayThread hiển thị nó. Ở đây tồn tại một điều kiện Race. Điều kiện cuộc đua có thể được giải quyết bằng cách sử dụng Đồng bộ hóa


0

Một điều kiện cuộc đua là một tình huống không mong muốn xảy ra khi hai hoặc nhiều quá trình có thể truy cập và thay đổi dữ liệu được chia sẻ cùng một lúc. Nó xảy ra do có các truy cập xung đột vào tài nguyên. Vấn đề phần quan trọng có thể gây ra tình trạng chủng tộc. Để giải quyết tình trạng quan trọng trong quá trình, chúng tôi chỉ đưa ra một quy trình tại một thời điểm thực hiện phần quan trọng.

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.