2011-02-08 22 views
5

Có rất nhiều câu hỏi về cách thực hiện bộ đếm tham chiếu an toàn chủ đề. Và câu trả lời được bình chọn rất phổ biến là: "sử dụng tăng/giảm nguyên tử". Ok, đây là một cách tốt để đọc và viết refCounter whitout thread khác thay đổi nó ở giữa. Nhưng.Một câu hỏi khác về đếm số đếm an toàn của chủ đề

Mã của tôi là:

void String::Release() 
{ 
    if (0 == AtomicDecrement(&refCounter))) 
     delete buffer; 
} 

So. Tôi giảm và đọc refCounter trong an toàn. Nhưng điều gì sẽ xảy ra nếu các chủ đề khác sẽ TĂNG TRƯỞNG của tôi trong khi tôi so sánh nó với số không ????

Tôi có sai không?

EDIT: (ví dụ)

String* globalString = new String(); // refCount == 1 after that. 

// thread 0: 
delete globalString; 
    // This invokes String::Release(). 
    // After AtomicDecrement() counter becomes zero. 
    // Exactly after atomic decrement current thread switches to thread 1. 

// thread 1: 
String myCopy = *globalString; 
    // This invokes AddRef(); 
    // globalString is alive; 
    // internal buffer is still not deleted but refCounter is zero; 
    // We increment and switch back to thread 0 where buffer will be 
    // succefully deleted; 

Tôi có sai lầm?

+2

Làm thế nào thread khác có thể tăng bộ đếm nếu nó không có một tham chiếu đến đối tượng ? Giá trị bằng 0 theo nghĩa đen có nghĩa là "không còn tham chiếu". –

Trả lời

1

Ví dụ của bạn có vẻ phù hợp với tôi.

Tuy nhiên, vấn đề ở đây không phải là về hoạt động nguyên tử, nhưng xóa thủ công một đối tượng và sau đó tham chiếu một đối tượng sắp bị xóa. Điều gì xảy ra nếu số tham chiếu thay vì là 1, là 8 ?.

Bạn cần phải tránh xóa và vô hiệu hóa đối tượng theo cách thủ công và sử dụng tốt hơn một số con trỏ thông minh triển khai nhận biết đồng thời để xử lý việc đếm tham chiếu.

Bất cứ khi nào con trỏ phát hiện số lần truy cập bằng không, bạn cần khóa đối tượng để tránh bị tham chiếu bởi chuỗi khác, giống như double-checked locking để khởi tạo tham chiếu mới.

+2

Một chuỗi khác sẽ truy cập đối tượng như thế nào khi không có tham chiếu đến đối tượng bên trái? –

+1

@Jeremy, Như Anton đã nói về ví dụ câu hỏi, nếu một luồng gọi phương thức Release() và, ngay sau cuộc gọi AtomicDecrement và trước lệnh delete một luồng khác cố gắng lấy một tham chiếu, số lần truy cập sẽ bằng 0 nhưng số thứ hai thread sẽ nhận được tham chiếu, tăng số lượng refcount ngay trước khi xóa, xóa một đối tượng với một refcount == 1. Đó là một trường hợp rất không thể xảy ra-nhưng-không-không thể. – vz0

+0

Cảm ơn mọi người. Nó thực sự là một vấn đề làm cho globalString thread-safe và không phải là bộ đệm bên trong. Vì vậy, như vz0 đề nghị tôi nên khóa globalString đầu tiên trước khi cố gắng làm việc với nó. P.S. Chuỗi chỉ là một ví dụ, trong mã thực sự của tôi, tôi có một chút phụ thuộc phức tạp hơn. –

2

Hãy cẩn thận!

Không đủ để bảo vệ biến như bộ đếm tham chiếu giúp quản lý vòng đời của thứ gì đó lớn hơn.

Tôi đã nhìn thấy mã như một trong câu hỏi của bạn mà kết thúc lên khá xấu ...

Trong trường hợp của bạn không phải là duy nhất mà ai đó có thể tăng bộ đếm sau khi so sánh của bạn, nhưng một số chủ đề có thể nhận được truy cập với giá trị 1, sau đó bạn giảm giá trị và DELETE bộ đệm và bộ nhớ khác đề sử dụng xóa ... CRASH

my2c

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