Tôi có nên quan tâm đến các điều kiện chủng tộc mà gần như chắc chắn không có cơ hội xảy ra?


52

Chúng ta hãy xem xét một cái gì đó giống như một ứng dụng GUI trong đó luồng chính đang cập nhật giao diện người dùng gần như ngay lập tức và một số luồng khác đang bỏ phiếu dữ liệu qua mạng hoặc một cái gì đó được đảm bảo mất 5-10 giây để hoàn thành công việc.

Tôi đã nhận được nhiều câu trả lời khác nhau cho vấn đề này, nhưng một số người nói rằng nếu đó là điều kiện chủng tộc của sự bất khả thi về mặt thống kê, thì đừng lo lắng về điều đó, nhưng những người khác đã nói rằng thậm chí còn có 10 -53 % (tôi là đứa trẻ bạn không biết về các con số, đây là những gì tôi đã nghe) về một số phép thuật voodoo xảy ra do điều kiện chủng tộc, luôn luôn có được / giải phóng các khóa trên luồng cần nó.

Quan điểm của bạn là gì? Đó có phải là một thực hành lập trình tốt để xử lý tình trạng chủng tộc trong các tình huống thống kê không thể như vậy? hoặc sẽ hoàn toàn không cần thiết hoặc thậm chí phản tác dụng khi thêm nhiều dòng mã để cản trở khả năng đọc?


21
Khi mọi người nói rõ những cơ hội như vậy, tại sao không ai hỏi về cách giáo dục của người nêu con số đó? Bạn cần một nền giáo dục chính thức về thống kê trước khi bạn có thể sao lưu với một số như thế.
Pieter B

27
Là một nhà vật lý, p <1E-140 có nghĩa là p = 0. Sẽ không xảy ra trong vũ trụ này. 0,0000000000000000000000000000000000000000000000000000001% lớn hơn rất nhiều .
MSalters

15
Đảm bảo điều kiện cuộc đua này không thể dẫn đến việc ai đó sẵn sàng đánh sập ứng dụng của bạn. Đây có thể là nguyên nhân của một vấn đề bảo mật.
to nướng_flakes

27
Một trong một triệu cơ hội xảy ra chín lần trong số mười.
Kaz Dragon

27
"gần như chắc chắn không có cơ hội xảy ra?" có nghĩa là nó xảy ra trong sản xuất lúc 3 giờ sáng và rất có thể là rất đắt.

Câu trả lời:


137

Nếu nó thực sự là một sự kiện 1 trong 10 ^ 55, thì sẽ không cần phải viết mã cho nó. Điều đó có nghĩa là nếu bạn thực hiện thao tác 1 triệu lần một giây, bạn sẽ gặp một lỗi sau mỗi 3 * 10 ^ 41 năm, tức là khoảng 10 ^ 31 lần tuổi của vũ trụ. Nếu ứng dụng của bạn có lỗi chỉ một lần trong mỗi nghìn tỷ tỷ tỷ tuổi của vũ trụ, điều đó có lẽ đủ đáng tin cậy.

Tuy nhiên, tôi sẽ đánh cuộc rất nhiều rằng lỗi không ở đâu gần như không thể xảy ra. Nếu bạn có thể hình dung ra lỗi, gần như chắc chắn rằng nó sẽ xảy ra ít nhất là đôi khi do đó làm cho nó có giá trị mã hóa chính xác để bắt đầu. Thêm vào đó, nếu bạn mã hóa các luồng chính xác ngay từ đầu để chúng có được và giải phóng các khóa một cách thích hợp, thì mã sẽ dễ bảo trì hơn nhiều trong tương lai. Bạn không phải lo lắng khi bạn thực hiện thay đổi mà bạn phải phân tích lại tất cả các điều kiện cuộc đua tiềm năng, tính toán lại xác suất của họ và đảm bảo với bản thân rằng họ sẽ không tái diễn.


66
Tôi đã nhắc nhở về một bình luận tôi đã đọc cách đây nhiều năm nhưng không thể tìm thấy bây giờ "Cơ hội 1 trong một triệu thường là vào thứ ba tới". +1 để nói rằng "không nơi nào gần như không thể".
Bevan

2
+1 cho cá cược. Cách tốt nhất để đối phó với các điều kiện chủng tộc là loại bỏ chúng.
Blrfl

10
@Bevan "Cơ hội 1 trong một triệu thường là vào thứ ba tới" ... trừ khi bạn đang chơi xổ số :)
dasblinkenlight

22
@dasblinkenlight Nhưng cơ hội ai đó chiến thắng ở hầu hết các giải xổ số tiếp cận 100%. Dự đoán ai , bây giờ đó là thách thức.
Bevan

3
@Bevan: Nhận xét đó chính xác là những gì đã diễn ra trong đầu tôi khi tôi đọc câu hỏi - đây là tài liệu tham khảo: blog.msdn.com/b/larryosterman/archive/2004/03/30/104165.aspx
Doc Brown

69

Từ quan điểm lợi ích chi phí, bạn chỉ nên viết mã bổ sung khi nó mang lại cho bạn đủ lợi ích.

Ví dụ: nếu điều tồi tệ nhất sẽ xảy ra nếu một chuỗi sai "thắng cuộc đua" là thông tin sẽ không hiển thị và người dùng sẽ cần nhấp vào "làm mới", đừng bận tâm đến điều kiện cuộc đua: phải viết rất nhiều mã không đáng để sửa một cái gì đó không đáng kể.

Mặt khác, nếu điều kiện cuộc đua có thể dẫn đến chuyển tiền không chính xác giữa các tài khoản ngân hàng, thì bạn phải bảo vệ chống lại điều kiện cuộc đua cho dù bạn cần viết bao nhiêu mã để giải quyết vấn đề này.


20
+1: Để phân biệt giữa "Thất bại trông giống như thất bại" và "Thất bại có vẻ như thành công". Thông tin không chính xác nghiêm trọng hơn nhiều, tùy thuộc vào tên miền.
deworde

2
+1 nó tạo ra sự khác biệt lớn về kết quả của điều kiện cuộc đua.
Cấp

+1 Hậu quả của điều kiện cuộc đua phải là yếu tố quyết định chính trong việc cần giải quyết. Một điều kiện cuộc đua có thể gây ra tai nạn máy bay khác xa với điều kiện có thể buộc người dùng mở lại một ứng dụng.
chọc

1
+1: Tôi sẽ nói rằng hậu quả có lẽ là những gì bạn nên phân tích và không phải là xác suất xảy ra. Nếu hậu quả không quan trọng, bạn có thể không phải xử lý tình trạng chủng tộc NGAY nếu nó rất phổ biến.
Leo

1
Nhưng đừng cho rằng việc sửa một điều kiện cuộc đua tự động có nghĩa là bạn phải viết thêm mã. Nó cũng có thể có nghĩa là loại bỏ một đoạn mã lỗi lớn và thay thế nó bằng một đoạn mã chính xác nhỏ hơn.
JesperE

45

Tìm một điều kiện cuộc đua là phần khó khăn. Có lẽ bạn đã dành gần như nhiều thời gian để viết câu hỏi này vì nó sẽ khiến bạn phải sửa nó. Nó không giống như nó làm cho nó ít đọc hơn nhiều. Các lập trình viên hy vọng sẽ thấy mã đồng bộ hóa trong các tình huống như vậy và thực sự có thể lãng phí nhiều thời gian hơn để tự hỏi tại sao nó không ở đó và nếu thêm nó sẽ sửa lỗi không liên quan của họ.

Theo như xác suất có liên quan, bạn sẽ ngạc nhiên. Tôi đã có một báo cáo lỗi tình trạng chủng tộc vào năm ngoái mà tôi không thể sao chép với hàng ngàn lần thử tự động, nhưng một hệ thống của một khách hàng đã thấy nó mọi lúc. Giá trị kinh doanh của việc dành 5 phút để khắc phục ngay bây giờ, so với khả năng khắc phục lỗi "không thể" trong quá trình cài đặt của khách hàng, khiến cho sự lựa chọn trở nên vô nghĩa.


1
Cái này cũng vậy! Tránh để các lập trình viên khác suy ngẫm về các vấn đề có thể xảy ra khi đọc mã của bạn, bằng cách làm những gì cần thiết (ngay cả khi nó 'không có khả năng' thất bại).
Casey Kuball

Quan điểm của bạn được thực hiện tốt (các bản sửa lỗi được thực hiện nhanh hơn và rẻ hơn so với các bản sửa lỗi được thực hiện sau đó) ngoại trừ việc sẽ không bao giờ chỉ là "5 phút để sửa ngay bây giờ".
iconoclast

2
+1 để chỉ ra rằng xác suất của điều kiện cuộc đua có thể phụ thuộc vào nhiều yếu tố, do đó, ngay cả khi cấu hình của bạn có vẻ không ổn , nó có thể xảy ra thường xuyên hơn trên hệ thống khách hàng / trên hệ điều hành khác / trong phiên bản tiếp theo, v.v.
sleske

27

Lấy và giải phóng các ổ khóa. Xác suất thay đổi, thuật toán thay đổi. Đó là một thói quen xấu để có được, và khi có điều gì đó không ổn, bạn không cần phải dừng lại và tự hỏi liệu bạn có sai tỷ lệ không ...


6
+1 cho các thuật toán thay đổi. Ngay bây giờ, khi bạn nhận thức được điều kiện cuộc đua, xác suất thấp. Sau một năm, khi bạn quên điều kiện cuộc đua, bạn có thể thay đổi mã của mình, điều này làm thay đổi đáng kể thời gian và xác suất xảy ra lỗi.
Phil

13

và một số luồng khác đang bỏ phiếu dữ liệu qua mạng hoặc một cái gì đó được đảm bảo mất 5-10 giây để hoàn thành công việc.

Cho đến khi ai đó giới thiệu một lớp bộ nhớ đệm để cải thiện hiệu suất. Đột nhiên, bước đi khác kết thúc gần ngay lập tức và điều kiện cuộc đua biểu hiện thường xuyên hơn không.

Chính xác thì điều này đã xảy ra vài tuần trước, mất khoảng 2 ngày để nhà phát triển tìm ra lỗi.

Luôn luôn sửa điều kiện cuộc đua nếu bạn nhận ra chúng.


8

Đơn giản vs chính xác.

Trong nhiều trường hợp, sự đơn giản hơn hẳn tính chính xác. Đó là một vấn đề chi phí.

Ngoài ra, điều kiện chủng tộc là những điều khó chịu có xu hướng không tuân theo các số liệu thống kê đơn giản. Mọi thứ đều ổn cho đến khi một số đồng bộ hóa dường như không liên quan khác khiến tình trạng cuộc đua của bạn đột nhiên xảy ra một nửa thời gian. Trừ khi bạn bật nhật ký hoặc gỡ lỗi mã tất nhiên.

Một giải pháp thay thế thực dụng để ngăn chặn tình trạng chủng tộc (có thể khó khăn) có thể là phát hiện và ghi lại nó (phần thưởng cho việc không thành công và sớm). Nếu nó không bao giờ xảy ra, bạn mất ít. Nếu nó thực sự xảy ra, bạn có một lý do chắc chắn để dành thêm thời gian để sửa nó.


1
+1 để đăng nhập và thất bại sớm nếu sửa nó hoàn toàn quá phức tạp.
Martin Ba

Trong nhiều trường hợp, sự đơn giản hơn hẳn. Đồng bộ hóa gần như không bao giờ trong số những trường hợp đó. Nó hầu như sẽ luôn quay lại cắn bạn (hoặc anh chàng tội nghiệp được giao nhiệm vụ duy trì mã của bạn) sau đó.
thiệu lại vào

@reirab Tôi không đồng ý. Nếu bạn xem xét các sự kiện không thường xuyên, thì thất bại đăng nhập là hiệu quả chi phí. Một ví dụ: nếu ứng dụng điện thoại của bạn có tỷ lệ thất bại 1/100 (sự cố) nếu người dùng đang chuyển đổi mạng theo chuyển đổi tháng chính xác (1/31 23:59:00 -> 2/1 00:00:00), bạn Có lẽ tôi sẽ không bao giờ nghe về nó. Nhưng sau đó, khả năng xảy ra sự cố 1/10 ^ 9 khi kết nối trên máy chủ là không thể chấp nhận được. Nó phụ thuộc.
ptyx

7

Nếu điều kiện chủng tộc của bạn liên quan đến bảo mật, bạn nên luôn luôn mã để ngăn chặn nó.

Một ví dụ phổ biến là điều kiện cuộc đua với việc tạo / mở tệp trong unix, trong một số trường hợp có thể dẫn đến các cuộc tấn công leo thang đặc quyền nếu chương trình với điều kiện cuộc đua đang chạy với các đặc quyền cao hơn so với người dùng tương tác với nó, như quy trình trình nền hệ thống hoặc tệ hơn nữa, hạt nhân.

Ngay cả khi một điều kiện cuộc đua có cơ hội xảy ra ngẫu nhiên 10 ^ (- 80) , thì đó cũng có thể là trường hợp một kẻ tấn công quyết tâm có cơ hội tốt để tạo ra các điều kiện như vậy một cách có chủ ý và giả tạo.


6

Therac-25!

Các nhà phát triển trong dự án Therac-25 khá tự tin về thời gian giữa giao diện người dùng và vấn đề liên quan đến giao diện trong máy XRAY trị liệu.

Họ không nên có.

Bạn có thể tìm hiểu thêm về thảm họa phần mềm sinh tử nổi tiếng này tại:

http://www.youtube.com/watch?v=izGSOsAGIVQ

hoặc là

http://en.wikipedia.org/wiki/Therac-25

Ứng dụng của bạn có thể ít nhạy cảm hơn với thất bại so với các thiết bị y tế. Một phương pháp hữu ích là đánh giá mức độ rủi ro là sản phẩm của khả năng xảy ra và chi phí xảy ra trong vòng đời của sản phẩm cho tất cả các đơn vị có thể được sản xuất.

Nếu bạn đã chọn xây dựng mã của mình để tồn tại (và có vẻ như bạn có), bạn nên xem xét luật Moore có thể dễ dàng loại bỏ một số không trong vài năm khi các máy tính bên trong hoặc bên ngoài hệ thống của bạn nhanh hơn. Nếu bạn gửi hàng ngàn bản sao, hãy bỏ qua nhiều số không. Nếu người dùng thực hiện thao tác này hàng ngày (hoặc hàng tháng) trong nhiều năm, hãy lấy đi một vài chi tiết. Nếu nó được sử dụng ở nơi Google có sẵn sợi thì sao? Nếu rác UI thu thập hoạt động GUI giữa, điều đó có ảnh hưởng đến cuộc đua không? Bạn có đang sử dụng thư viện Nguồn mở hoặc Windows phía sau GUI của mình không? Có thể cập nhật ở đó ảnh hưởng đến thời gian?

Semaphores, khóa, mutexes, đồng bộ hóa rào cản là một trong những cách để đồng bộ hóa các hoạt động giữa các luồng. Có khả năng nếu bạn không sử dụng chúng, một người khác duy trì chương trình của bạn có thể và sau đó các giả định khá nhanh về mối quan hệ giữa các luồng có thể thay đổi và tính toán về điều kiện cuộc đua có thể bị vô hiệu.

Tôi khuyên bạn nên đồng bộ hóa một cách rõ ràng bởi vì trong khi bạn có thể không bao giờ thấy nó tạo ra vấn đề, thì một khách hàng có thể. Ngoài ra, ngay cả khi điều kiện cuộc đua của bạn không bao giờ xảy ra, điều gì sẽ xảy ra nếu bạn hoặc tổ chức của bạn được gọi ra tòa để bảo vệ mã của bạn (vì Toyota có liên quan đến Prius vài năm trước). Phương pháp của bạn càng kỹ lưỡng, bạn sẽ có giá vé tốt hơn. Có thể tốt hơn khi nói "chúng tôi bảo vệ chống lại trường hợp không thể xảy ra như thế này ..." hơn là nói, "chúng tôi biết mã của chúng tôi sẽ thất bại, nhưng chúng tôi đã viết ra phương trình này để cho thấy nó sẽ không xảy ra trong cuộc sống của chúng tôi. "

Nghe có vẻ như tính toán xác suất đến từ người khác. Họ có biết mã của bạn không và bạn có biết họ đủ tin tưởng rằng không có lỗi nào không? Nếu tôi tính độ tin cậy 99.99997% cho một thứ gì đó, tôi cũng có thể nghĩ lại các lớp thống kê đại học của mình và nhớ rằng tôi không phải lúc nào cũng nhận được 100%, và rút lại khá nhiều phần trăm cho ước tính độ tin cậy cá nhân của riêng tôi.


1
+1 để đề cập đến Therac-25. Nhiều bài học quan trọng ở đây.
Stuart Marks

Mặc dù tôi nghĩ rằng đây là một câu trả lời hay, bạn có thể lập luận rằng dự án GUI sở thích của bạn chắc chắn sẽ không khiến mọi người chết nếu bạn không loại bỏ điều kiện cuộc đua.
marktani

Tôi không tranh luận nhiều, nhưng nếu là tôi, tôi có thể lập luận rằng bất cứ khi nào chúng ta viết mã, chúng ta nên viết đúng. Nếu chúng ta có thể thực hành đưa các điều kiện chủng tộc ra khỏi các dự án sở thích của mình, nơi mã đơn giản hơn và có lẽ chúng ta là tác giả duy nhất, chúng ta sẽ sẵn sàng hơn nhiều khi chúng ta giải quyết các dự án công việc trong đó công việc của một số tác giả cần được tích hợp với nhau.
DeveloperDon

4

nó sẽ hoàn toàn không cần thiết hoặc thậm chí phản tác dụng khi thêm nhiều dòng mã để cản trở khả năng đọc?

Đơn giản chỉ tốt khi nó cũng đúng. Vì mã này không chính xác, các lập trình viên trong tương lai chắc chắn sẽ xem xét nó khi tìm kiếm một lỗi liên quan.

Dù bạn xử lý bằng cách nào (bằng cách đăng nhập, ghi lại tài liệu hoặc thêm khóa - điều này phụ thuộc vào chi phí), bạn sẽ tiết kiệm thời gian cho các lập trình viên khác khi xem mã.


3

Điều này sẽ phụ thuộc vào bối cảnh. Nếu đó là một trò chơi iPhone bình thường, có lẽ là không. Hệ thống điều khiển chuyến bay cho phương tiện không gian có người lái tiếp theo, có lẽ. Tất cả phụ thuộc vào hậu quả là gì nếu kết quả 'xấu' xảy ra được đo bằng chi phí ước tính để sửa nó.

Hiếm khi có câu trả lời "một kích thước phù hợp với tất cả" cho các loại câu hỏi này vì chúng không phải là câu hỏi lập trình, mà thay vào đó là câu hỏi kinh tế.


3
"Hệ thống điều khiển chuyến bay cho phương tiện không gian có người lái tiếp theo" DEFINITELY .
deworde

có lẽ ... chắc chắn ... nó phụ thuộc vào người đã ở trong tên lửa :-)
GrandmasterB

3

Vâng, mong đợi những điều bất ngờ. Tôi đã dành hàng giờ (theo mã người khác ^^) theo dõi các điều kiện không bao giờ xảy ra.

Những thứ như luôn có một cái khác, luôn có một mặc định trong trường hợp, khởi tạo các biến (vâng, thực sự .. lỗi xảy ra từ điều này), kiểm tra các vòng lặp của bạn để biết các biến được sử dụng lại cho mỗi lần lặp, v.v.

Nếu bạn lo lắng về các vấn đề luồng cụ thể, hãy đọc blog, bài viết và sách về chủ đề này. Chủ đề hiện tại dường như là dữ liệu bất biến.


3

Chỉ cần sửa nó.

Tôi đã thấy chính xác điều này. Một luồng quản lý để thực hiện một yêu cầu mạng đến một máy chủ thực hiện tra cứu cơ sở dữ liệu phức tạp và trả lời trước khi luồng khác đã đến dòng mã tiếp theo. Nó xảy ra.

Một số khách hàng ở đâu đó sẽ quyết định một ngày nào đó sẽ chạy thứ gì đó chiếm hết thời gian CPU cho luồng "nhanh" trong khi để luồng chậm chạy, và bạn sẽ rất tiếc :)


1

Nếu bạn đã nhận ra một điều kiện cuộc đua không thể xảy ra, ít nhất là ghi lại nó trong mã!

EDIT: Tôi nên thêm rằng tôi sẽ sửa nó nếu có thể, nhưng tại thời điểm viết ở trên, không có câu trả lời nào khác nói rõ ràng ít nhất là ghi lại vấn đề trong mã.


1
Đúng, và ít nhất hãy thử và phát hiện nó và đăng nhập nó nếu nó xảy ra. IMHO hoàn toàn ổn để tránh mọi lỗi. Nhưng ít nhất hãy cho ai đó biết rằng nó đã xảy ra, và giả định của bạn rằng nó sẽ không bị nhầm lẫn.
Steve Bennett

0

Tôi nghĩ rằng nếu bạn đã biết làm thế nào và tại sao nó có thể xảy ra, cũng có thể đối phó với nó. Đó là nếu nó không chiếm nhiều tài nguyên.


0

Tất cả phụ thuộc vào hậu quả của tình trạng chủng tộc là gì. Tôi nghĩ rằng những người trả lời câu hỏi của bạn là chính xác cho dòng công việc của họ. Của tôi là động cơ cấu hình bộ định tuyến. Đối với tôi, điều kiện chủng tộc hoặc làm cho các hệ thống đứng yên, bị hỏng hoặc không được định cấu hình mặc dù nó nói rằng nó đã thành công. Tôi luôn sử dụng semaphores cho mỗi bộ định tuyến để tôi không phải dọn dẹp bất cứ thứ gì bằng tay.

Tôi nghĩ rằng một số mã GUI của tôi vẫn thiên về các điều kiện chủng tộc theo cách mà người dùng có thể bị lỗi vì điều kiện cuộc đua đã xảy ra, nhưng tôi sẽ không có bất kỳ khả năng nào như vậy nếu có khả năng bị hỏng dữ liệu hoặc xử lý sai ứng dụng sau sự kiện đó.


0

Đủ buồn cười, tôi đã gặp vấn đề này gần đây. Tôi thậm chí không nhận ra một điều kiện chủng tộc là có thể trong hoàn cảnh của tôi. Điều kiện cuộc đua chỉ xuất hiện khi bộ xử lý đa lõi trở thành chuẩn mực.

Kịch bản đại khái là như thế này. Một trình điều khiển thiết bị đưa ra các sự kiện cho phần mềm để xử lý. Kiểm soát phải quay lại trình điều khiển thiết bị càng sớm càng tốt để ngăn thời gian chờ trên thiết bị. Để đảm bảo điều này, sự kiện đã được ghi lại và xếp hàng trong một luồng riêng biệt.

Receive event from device:
{
    Record event details.
    Enqueue event in the queuing thread.
    Acknowledge the event.
}

Queueing thread receives an event:
{
    Retrieve event details.
    Process event.
    Send next command to device.
}

Điều này làm việc tốt trong nhiều năm. Sau đó, đột nhiên nó sẽ thất bại trong một số cấu hình nhất định. Nó chỉ ra rằng luồng hàng đợi hiện đang chạy thực sự song song với luồng xử lý sự kiện, thay vì chia sẻ thời gian của một bộ xử lý. Nó quản lý để gửi lệnh tiếp theo đến thiết bị trước khi sự kiện được xác nhận, gây ra lỗi ngoài chuỗi.

Vì nó chỉ ảnh hưởng đến một khách hàng trong một cấu hình, tôi xấu hổ đặt Thread.Sleep(1000)vấn đề ở đâu. Không có vấn đề gì kể từ đó.

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.