8

Hãy tha thứ cho tiêu đề hơi hài hước của tôi. Tôi sử dụng hai định nghĩa khác nhau của từ 'an toàn' trong đó (hiển nhiên).Có an toàn để sử dụng các chức năng chủ đề 'Không an toàn' không?

Tôi khá mới mẻ để đọc luồng (tốt, tôi đã sử dụng luồng trong nhiều năm, nhưng chỉ có các dạng rất đơn giản của nó). Bây giờ tôi đang phải đối mặt với challange của việc thực hiện bằng văn bản song song của một số thuật toán, và các chủ đề cần phải làm việc trên cùng một dữ liệu. Xem xét lỗi newbie sau đây:

const 
    N = 2; 

var 
    value: integer = 0;  

function ThreadFunc(Parameter: Pointer): integer; 
var 
    i: Integer; 
begin 
    for i := 1 to 10000000 do 
    inc(value); 
    result := 0; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    threads: array[0..N - 1] of THandle; 
    i: Integer; 
    dummy: cardinal; 
begin 

    for i := 0 to N - 1 do 
    threads[i] := BeginThread(nil, 0, @ThreadFunc, nil, 0, dummy); 

    if WaitForMultipleObjects(N, @threads[0], true, INFINITE) = WAIT_FAILED then 
    RaiseLastOSError; 

    ShowMessage(IntToStr(value)); 

end; 

Người mới bắt đầu có thể mong đợi mã ở trên để hiển thị thông báo 20000000. Thực tế, trước tiên, value bằng 0 và sau đó chúng tôi inc20000000 lần. Tuy nhiên, vì thủ tục inc không phải là 'nguyên tử', hai chủ đề sẽ xung đột (tôi đoán rằng inc thực hiện ba điều: nó đọc, nó tăng dần và tiết kiệm), và vì vậy rất nhiều các số inc sẽ bị mất hiệu quả '. Giá trị điển hình tôi nhận được từ mã ở trên là 10030423.

Cách giải quyết đơn giản nhất là sử dụng InterlockedIncrement thay vì Inc (sẽ chậm hơn nhiều trong ví dụ ngớ ngẩn này, nhưng đó không phải là vấn đề). Một cách giải quyết khác là đặt inc bên trong một phần quan trọng (có, điều đó cũng sẽ rất chậm trong ví dụ ngớ ngẩn này).

Hiện tại, trong hầu hết các thuật toán thực sự, xung đột không phổ biến như vậy. Trong thực tế, họ có thể rất không phổ biến. Một trong các thuật toán của tôi tạo ra DLA fractals và một trong các biến mà tôi inc mỗi bây giờ và sau đó là số lượng các hạt hấp phụ. Xung đột ở đây rất hiếm, và, quan trọng hơn, tôi thực sự không quan tâm nếu biến số tiền lên đến 20000000, 20000008, 20000319, hoặc 19999496. Do đó, nó hấp dẫn không để sử dụng InterlockedIncrement hoặc các phần quan trọng, vì chúng chỉ bloat mã và làm cho nó (nhẹ) chậm hơn không (như xa như tôi có thể nhìn thấy) lợi ích.

Tuy nhiên, câu hỏi của tôi là: có thể có hậu quả nghiêm trọng hơn của xung đột hơn giá trị hơi 'không chính xác' của biến gia tăng không? Ví dụ: chương trình có thể gặp sự cố không?

Phải thừa nhận rằng, câu hỏi này có vẻ ngớ ngẩn, cho, sau khi tất cả, chi phí của việc sử dụng InterlockedIncrement thay vì inc là khá thấp (trong nhiều trường hợp, nhưng không phải tất cả!), Và vì vậy nó là (có lẽ) ngu ngốc không để chơi an toàn. Nhưng tôi cũng cảm thấy rằng nó sẽ là tốt để biết làm thế nào điều này thực sự làm việc trên một mức độ lý thuyết, vì vậy tôi vẫn nghĩ rằng câu hỏi này là rất thú vị.

+0

Tôi đoán rằng sự sụt giảm là do tiêu đề hài hước. –

Trả lời

10

Chương trình của bạn sẽ không bao giờ gặp sự cố do cuộc đua tăng số nguyên chỉ được sử dụng làm số. Tất cả những gì có thể xảy ra là bạn không nhận được câu trả lời chính xác . Rõ ràng nếu bạn đang sử dụng số nguyên như một chỉ mục vào một mảng, hoặc có lẽ nó là một con trỏ thì bạn có thể có vấn đề.

Trừ khi bạn tăng giá trị này cực kỳ thường xuyên, thật khó để tưởng tượng rằng một khoản tăng liên động sẽ đủ tốn kém để bạn nhận thấy sự khác biệt hiệu suất.

Phương pháp tiếp cận hiệu quả nhất là để có được mỗi chủ đề duy trì số lượng riêng của mình. Sau đó, tổng hợp tất cả các chủ đề cá nhân đếm khi bạn tham gia các chủ đề ở phần cuối của phép tính. Bằng cách đó bạn sẽ có được tốt nhất của cả hai thế giới. Không tranh chấp về gia số và câu trả lời đúng. Tất nhiên, bạn cần phải thực hiện các biện pháp để đảm bảo rằng bạn không bị bắt gặp bởi false sharing.

+0

Cảm ơn bạn đã trả lời. Về phần cuối, tôi biết đây là một ví dụ ngớ ngẩn, nhưng tôi chỉ muốn xác nhận giả thuyết rằng điều tồi tệ nhất có thể xảy ra trong một trường hợp như thế này là kết quả sai (hoặc 'hơi') . –

+0

Rủi ro là tất nhiên cũng dựa trên những gì bạn làm với số đó. Nếu nó chỉ để hiển thị, đó là không có vấn đề, nhưng nó có thể là một vấn đề nếu bạn sử dụng nó để lặp hoặc các công cụ khác, nơi một số lượng sai có thể có nghĩa là rò rỉ bộ nhớ hoặc truy cập bộ nhớ đã được deallocated –

+0

@Marco: Tất nhiên. Tôi chỉ sợ rằng 'xung đột' có thể có khả năng gây nguy hiểm. –

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