2012-04-22 38 views
18

Tôi đang viết con trỏ được chia sẻ xâm nhập và tôi đang sử dụng các cơ sở C++ 11 <atomic> để tham khảo. Dưới đây là các mảnh vỡ có liên quan của mã của tôi:C++ 11 nguyên tử và số tham chiếu con trỏ chia sẻ xâm nhập

//... 
mutable std::atomic<unsigned> count; 
//... 

void 
SharedObject::addReference() const 
{ 
    std::atomic_fetch_add_explicit (&count, 1u, 
     std::memory_order_consume); 
} 

void 
SharedObject::removeReference() const 
{ 
    bool destroy; 

    destroy = std::atomic_fetch_sub_explicit (&count, 1u, 
     std::memory_order_consume) == 1; 

    if (destroy) 
     delete this; 
} 

Tôi đã bắt đầu với memory_order_acquirememory_order_release đầu tiên nhưng sau đó tôi đã thuyết phục bản thân mình rằng memory_order_consume nên đủ tốt. Sau khi cân nhắc thêm, có vẻ như với tôi rằng ngay cả memory_order_relaxed cũng sẽ hoạt động.

Bây giờ, câu hỏi là liệu tôi có thể sử dụng memory_order_consume cho các hoạt động hoặc tôi có thể sử dụng đặt hàng yếu hơn (memory_order_relaxed) hay tôi nên sử dụng đặt hàng khắt khe hơn?

+0

Vì bộ đếm cơ bản hoạt động như một khóa đệ quy cho câu lệnh 'delete', tôi muốn nói rằng" có được "trong' addReference' và "release" trong 'removeReference' là thứ tự đúng. Nhưng 'addReference' của bạn cũng nên đảm bảo rằng bộ đếm không phải là số không! –

+0

@KerrekSB: Bộ đếm có thể bằng không trong 'addReference()' sau khi đối tượng được tạo đầu tiên trước khi nó được gán cho một 'SharedPtr <>'. Có được/phát hành ngữ nghĩa dường như nó luôn luôn hoạt động. Nhưng nó không thể sử dụng ràng buộc đặt hàng yếu hơn và tại sao không? – wilx

+0

Về số không: Giả sử refcount là 1. Bây giờ thread 1 muốn xóa đối tượng và các cuộc gọi trừ đi. Nếu tại thời điểm này thread 2 muốn * tăng * số lượng chủ đề, nó tăng không đến một, nhưng thread 1 sẽ đi trước và xóa các đối tượng anyway. Điều đó nên tránh. –

Trả lời

20
void 
SharedObject::addReference() const 
{ 
    std::atomic_fetch_add_explicit (&count, 1u, std::memory_order_relaxed); 
} 

void 
SharedObject::removeReference() const 
{ 
    if (std::atomic_fetch_sub_explicit (&count, 1u, std::memory_order_release) == 1) { 
     std::atomic_thread_fence(boost::memory_order_acquire); 
     delete this; 
    } 
} 

Bạn muốn sử dụng atomic_thread_fence như vậy mà delete là đúng sau khi fetch_sub. Reference

Trích dẫn từ các văn bản liên kết:

Tăng truy cập tài liệu tham khảo luôn có thể được thực hiện với memory_order_relaxed: tài liệu tham khảo mới cho một đối tượng chỉ có thể được hình thành từ một tài liệu tham khảo hiện có, và đi qua một tài liệu tham khảo hiện tại từ một luồng này đến chủ đề khác phải cung cấp mọi đồng bộ được yêu cầu.

Điều quan trọng là phải thực thi bất kỳ quyền truy cập nào có thể vào đối tượng trong một chuỗi (thông qua tham chiếu hiện tại) trước khi xóa đối tượng trong một luồng khác. Điều này đạt được bằng thao tác "release" sau khi bỏ tham chiếu (bất kỳ truy cập nào đối tượng thông qua tham chiếu này rõ ràng phải xảy ra trước đó) và thao tác "có được" trước khi xóa đối tượng.

Nó sẽ có thể sử dụng memory_order_acq_rel cho sự vận hành fetch_sub , nhưng kết quả này trong không cần thiết "mua lại" hoạt động khi truy cập tham khảo vẫn chưa đạt được không và có thể áp đặt một hiệu suất phạt.

+0

Trong khi tôi đã chấp nhận câu trả lời và thực hiện con trỏ xâm nhập của tôi theo cách đó, câu nói khiến tôi suy nghĩ một chút và đây là một câu hỏi khác. Điều gì về thư giãn decrement để 'memory_order_relaxed' và làm cho các chi nhánh thực sự của' if() 'sử dụng' memory_order_acq_rel'? – wilx

+0

với '_relaxed' của bạn, sau đó' _acq_rel', không có thứ tự nghiêm ngặt 'fetch_sub (_relaxed)' và 'hàng rào (_acq_rel)' rồi 'xóa'. Bạn có thể quan tâm đến [trang] này (http://www.chaoticmind.net/~hcb/projects/boost.atomic/doc/atomic/thread_coordination.html). – user2k5

+0

Ok, sau khi đọc trang, tôi nghĩ rằng tôi hiểu rằng nó không thể là 'fetch_sub (_relaxed)'. Đó là vì bất kỳ hoạt động '_relaxed' nào cũng không được đặt hàng trước các hoạt động khác. Nhưng còn 'fetch_sub (_consume)' và 'fence (_acq_rel)' thì sao? Có vẻ như với tôi rằng 'fetch_sub (_consume)' đặt ra một rào cản sắp xếp trình biên dịch và 'hàng rào (_acq_rel)' yêu cầu tất cả các tải và lưu trữ so với phần còn lại của máy và 'xóa' sau sẽ có chế độ xem nhất quán của bộ nhớ. Hoặc là tôi sai? – wilx

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