2013-06-11 33 views
16

Nếu tôi có một int duy nhất mà tôi muốn viết từ một chủ đề và đọc từ một chủ đề khác, tôi cần sử dụng std::atomic, để đảm bảo rằng giá trị của nó là nhất quán trên lõi, bất kể có hướng dẫn đọc hay không viết cho nó là khái niệm nguyên tử. Nếu không, có thể là lõi đọc có giá trị cũ trong bộ nhớ cache của nó và sẽ không thấy giá trị mới. Điều này có ý nghĩa với tôi.Làm thế nào để một mutex đảm bảo giá trị của biến là nhất quán giữa các lõi?

Nếu tôi có một số loại dữ liệu phức tạp không thể đọc/ghi thành nguyên tử, tôi cần phải bảo vệ quyền truy cập vào nó bằng cách sử dụng một số nguyên thủy đồng bộ hóa, chẳng hạn như std::mutex. Điều này sẽ ngăn chặn các đối tượng nhận được vào (hoặc được đọc từ) một trạng thái không phù hợp. Điều này có ý nghĩa với tôi.

Điều gì không có ý nghĩa đối với tôi là cách mutex giúp trợ giúp về vấn đề bộ nhớ đệm mà nguyên tử giải quyết. Họ dường như chỉ tồn tại để ngăn chặn truy cập đồng thời vào một số tài nguyên, nhưng không phải để truyền bá bất kỳ giá trị nào chứa trong tài nguyên đó tới bộ nhớ cache của lõi khác. Có một phần nào đó trong ngữ nghĩa của họ mà tôi đã bỏ lỡ mà giao dịch với điều này?

+0

Tôi không nhận được những gì bạn không nhận được. Nguyên tử có ngữ nghĩa [khóa toàn cầu mutex; làm op; mở khóa toàn cầu mutex]. Chỉ cần một số có hỗ trợ nội tại như vậy được thực hiện hoàn toàn và nhanh chóng. –

+0

Chỉ cần FYI - std :: nguyên tử hoạt động với tất cả các loại dữ liệu. Amusingly của nó chỉ không khóa miễn phí nếu nó quá phức tạp - nó rơi trở lại ổ khóa trong trường hợp đó. Xem chức năng thành viên 'is_lock_free()'. Tuy nhiên, bạn vẫn phải cẩn thận nếu bạn làm điều này thay vì khóa. –

+1

Balog, tôi hiểu ngữ nghĩa của mutexes, và tôi hiểu cách nguyên tử làm những gì họ làm, và tôi hiểu rằng trong C++ 11 họ chính thức có thêm ngữ nghĩa ngăn các lõi khác nhau giữ các giá trị cũ trong bộ đệm. Những gì tôi không hiểu là làm thế nào mutexes làm điều đó. Chúng ngăn chặn truy cập đồng thời vào một thứ, nhưng tôi đã không đọc bất cứ điều gì nói rằng điều đó sẽ có giá trị nhất quán trong bộ nhớ cache của các lõi khác nhau. –

Trả lời

4

Câu trả lời đúng cho điều này là các câu thần chú ảo thuật - ví dụ: Nó chỉ hoạt động. Việc thực hiện std :: nguyên tử cho mỗi nền tảng phải làm điều đúng.

Điều đúng là sự kết hợp của 3 phần.

Thứ nhất, trình biên dịch cần biết rằng nó không thể di chuyển hướng dẫn trên các ranh giới [thực tế trong một số trường hợp, nhưng giả sử rằng nó không]. Thứ hai, bộ nhớ cache/bộ nhớ phụ cần phải biết - điều này thường được thực hiện bằng cách sử dụng các rào cản bộ nhớ, mặc dù x86/x64 thường có bộ nhớ mạnh như vậy đảm bảo rằng điều này là không cần thiết trong phần lớn các trường hợp (đó là một lớn xấu hổ như là tốt đẹp của nó cho mã sai để thực sự đi sai).

Cuối cùng CPU cần biết nó không thể sắp xếp lại hướng dẫn. CPU hiện đại đang tích cực mạnh mẽ trong việc sắp xếp lại các hoạt động và đảm bảo trong trường hợp chỉ có một luồng rằng điều này là không đáng kể. Họ có thể cần thêm gợi ý rằng điều này không thể xảy ra ở những nơi nhất định.

Đối với hầu hết các CPU phần 2 và 3 đi xuống cùng một điều - một rào cản bộ nhớ ngụ ý cả hai.Phần 1 là hoàn toàn bên trong trình biên dịch, và là xuống để các nhà văn trình biên dịch để có được quyền.

Xem Herb Sutters nói 'Atomic Weapons' để biết thêm nhiều thông tin thú vị hơn.

+0

Điều này có vẻ giống như câu trả lời hoàn chỉnh nhất, cảm ơn! Thật không may, bây giờ có nghĩa là tôi cần đặt câu hỏi tiếp theo "cách rào cản bộ nhớ thực thi tính nhất quán" vì tôi không thấy cách ngăn chặn sắp xếp lại có thể đảm bảo CPU/lõi đảm bảo giá trị mà chúng đã lưu trữ được đồng bộ ... tuôn ra mọi thứ khi họ gặp phải một rào cản? Có lẽ chỉ là những thứ truy cập một vài hướng dẫn xung quanh rào cản? Tôi tưởng tượng câu trả lời một lần nữa là "ma thuật pixies" :) –

+0

Ngoài ra, xin chào Mike! Tôi nghĩ chúng tôi đã ở cùng nhau trong một thời gian ngắn sau khi tôi tham gia! –

+0

@BenHymers Cache đồng bộ hóa mọi lúc. Không có hướng dẫn đặc biệt để giữ bộ nhớ cache đồng bộ. Nó được thực hiện tự động và mọi lúc. – curiousguy

6

Tính nhất quán giữa các lõi được đảm bảo bằng memory barriers (cũng ngăn các hướng dẫn sắp xếp lại). Khi bạn sử dụng std::atomic, bạn không chỉ truy cập dữ liệu một cách nguyên tử, mà trình biên dịch (và thư viện) cũng chèn các rào cản bộ nhớ có liên quan.

Mutexes hoạt động theo cùng một cách: triển khai mutex (ví dụ: pthreads hoặc WinAPI hoặc những gì không) bên trong cũng chèn các rào cản bộ nhớ.

+1

Chính xác là rào cản bộ nhớ? Làm thế nào nó hoạt động? Hay đó là một câu hỏi riêng? – SirGuy

+1

Đó phải là tìm kiếm của Google;) –

+3

@GuyGreer: Theo ý kiến ​​của tôi, đó là một câu hỏi riêng, nhưng tôi thậm chí không chắc nó phù hợp với SO vì chủ đề quá rộng (điển hình "chúng tôi cần một cuốn sách toàn bộ trả lời rằng "). Một tìm kiếm trực tuyến thực sự là một khởi đầu tốt để có được những điều cơ bản, sau đó * câu hỏi * chính xác có thể được yêu cầu. – syam

4

Hầu hết các bộ xử lý đa lõi hiện đại (bao gồm x86 và x64) là cache coherent. Nếu hai lõi giữ cùng một vị trí bộ nhớ trong bộ nhớ cache và một trong số chúng cập nhật giá trị, thay đổi sẽ tự động được truyền sang bộ nhớ cache của lõi khác. Nó không hiệu quả (ghi vào cùng một dòng bộ nhớ cache cùng một lúc từ hai lõi thực sự chậm) nhưng không có sự kết hợp bộ nhớ cache thì sẽ rất khó để viết phần mềm đa luồng.

Và giống như syam cho biết, các rào cản bộ nhớ cũng được yêu cầu. Chúng ngăn cản trình biên dịch hoặc bộ xử lý truy cập lại bộ nhớ truy cập, và cũng buộc ghi vào bộ nhớ (hoặc ít nhất là vào bộ nhớ đệm), khi ví dụ một biến được giữ trong sổ đăng ký vì các trình biên dịch của trình biên dịch.

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