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 inc
nó 20000000
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ị.
Tôi đoán rằng sự sụt giảm là do tiêu đề hài hước. –