2014-12-02 16 views
14

Sự thất bại của đồng bộ hóa kiểu Dekker thường được giải thích với sắp xếp lại các hướng dẫn. Ví dụ: nếu chúng tôi viếtTại sao không phải là một hàng rào C++ 11 gain_release đủ để đồng bộ hóa Dekker?

atomic_int X; 
atomic_int Y; 
int r1, r2; 
static void t1() { 
    X.store(1, std::memory_order_relaxed) 
    r1 = Y.load(std::memory_order_relaxed); 
} 
static void t2() { 
    Y.store(1, std::memory_order_relaxed) 
    r2 = X.load(std::memory_order_relaxed); 
} 

Sau đó, tải có thể được sắp xếp lại với các cửa hàng, dẫn đến r1==r2==0.

Tôi đã chờ đợi một hàng rào acquire_release để ngăn chặn loại sắp xếp lại:

static void t1() { 
    X.store(1, std::memory_order_relaxed); 
    atomic_thread_fence(std::memory_order_acq_rel); 
    r1 = Y.load(std::memory_order_relaxed); 
} 
static void t2() { 
    Y.store(1, std::memory_order_relaxed); 
    atomic_thread_fence(std::memory_order_acq_rel); 
    r2 = X.load(std::memory_order_relaxed); 
} 

Tải trọng không thể di chuyển trên hàng rào và các cửa hàng không thể di chuyển bên dưới hàng rào, và do đó kết quả xấu cần được ngăn chặn .

Tuy nhiên, các thử nghiệm hiển thị r1==r2==0 vẫn có thể xảy ra. Có một giải thích dựa trên sắp xếp lại cho điều này? Lỗ hổng trong lý luận của tôi đâu?

Trả lời

8

Theo tôi được biết (chủ yếu là từ việc đọc Jeff Preshings blog), một atomic_thread_fence(std::memory_order_acq_rel) ngăn chặn bất kỳ reorderings trừ StoreLoad, nghĩa là, nó vẫn cho phép để sắp xếp lại một Store với một tiếp theo Load. Tuy nhiên, đây chính xác là sắp xếp lại mà phải được ngăn chặn trong ví dụ của bạn.

Chính xác hơn, một atomic_thread_fence(std::memory_order_acquire) ngăn ngừa sự sắp xếp lại của bất kỳ trước Load với bất kỳ tiếp theo Store và sau đó bất kỳ Load, nghĩa là, nó ngăn chặn LoadLoadLoadStore reorderings qua hàng rào.

Một atomic_thread_fence(std::memory_order_release) ngăn ngừa sự sắp xếp lại của bất kỳ tiếp theo Store với bất kỳ trước Store và bất kỳ trước Load, nghĩa là, nó ngăn chặn LoadStoreStoreStore reorderings qua hàng rào.

Một atomic_thread_fence(std::memory_order_acq_rel) sau đó ngăn cản sự kết hợp, ví dụ, nó ngăn cản LoadLoad, LoadStore, và StoreStore, có nghĩa là chỉ StoreLoad vẫn có thể xảy ra.

4

memory_order_acq_rel thực sự hoạt động giống như có được và giải phóng hàng rào tại cùng một vị trí. Nhưng vấn đề là họ không ngăn chặn tất cả các sắp xếp lại có thể, chúng ngăn chặn tải trọng hoặc các cửa hàng trước đó bị sắp xếp lại quanh hàng rào. Vì vậy, tải trước và các cửa hàng hậu quả vẫn có thể đi qua hàng rào.

Đồng bộ hóa Dekker, điều quan trọng là ngăn chặn ví dụ: tải từ được sắp xếp lại trước cửa hàng trong một chủ đề khác, tức là trước hàng rào. Bây giờ, hãy bỏ vòng lặp của bạn nơi đồng bộ hóa này xảy ra và bạn sẽ nhận được rằng tải từ lần lặp trước có thể rơi qua hàng rào trong lần lặp hiện tại.

memory_order_seq_cst hoạt động tốt cho đồng bộ hóa của Dekker vì nó ngăn không cho bất kỳ sắp xếp lại nào trong thời điểm này. Ví dụ: sử dụng thuật toán của Dekker và mfence để đánh cắp công việc.

Để hiểu rõ hơn, hãy xem hoạt ảnh tuyệt vời từ bài giảng Herb Sutter "Atomic<> weapons 1/2", tại 0:43.

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