2012-03-15 30 views
10

Tôi cần đọc/ghi 16 byte nguyên tử. Tôi thực hiện việc viết chỉ sử dụng cmpxchg16, có sẵn trên tất cả các bộ vi xử lý x64, ngoại trừ tôi nghĩ đến một bộ xử lý AMD tối nghĩa.Đọc 16 byte nguyên tử trên CPU x64

Bây giờ câu hỏi dành cho các giá trị 16 byte liên kết, chỉ được sửa đổi khi sử dụng cmpxchg16 (hoạt động giống như hàng rào bộ nhớ đầy đủ) có thể đọc được vị trí 16 byte đó là một nửa dữ liệu cũ và một nửa dữ liệu mới?

Miễn là tôi đọc bằng lệnh SSE (vì vậy luồng không thể bị gián đoạn ở giữa phần đọc) Tôi nghĩ rằng điều đó là không thể (ngay cả trong hệ thống numa đa xử lý) để đọc để xem dữ liệu không phù hợp. Tôi nghĩ nó phải là nguyên tử.

Tôi giả định rằng khi cmpxchg16 được thực hiện, nó sửa đổi 16 byte nguyên tử, không phải bằng cách viết hai khối 8 byte với tiềm năng cho các luồng khác để đọc ở giữa (thành thật mà nói tôi không thấy nó như thế nào có thể hoạt động nếu nó không phải là nguyên tử.)

Tôi có đúng không? Nếu tôi sai, có cách nào để làm một nguyên tử 16 byte đọc mà không cần đến khóa?

Lưu ý: Có couple similar questions here nhưng chúng không giải quyết trường hợp viết chỉ được thực hiện với cmpxchg16, vì vậy tôi cảm thấy đây là câu hỏi riêng biệt, chưa được trả lời.

Chỉnh sửa: Thực ra tôi nghĩ lý do của tôi đã bị lỗi. Lệnh tải SSE có thể được thực hiện như hai lần đọc 64 bit và có thể thực thi cmpxchg16 ở giữa hai lần đọc bởi một bộ xử lý khác.

+1

Nó đã được trả lời trong câu hỏi liên quan rằng 16-byte SSE đọc có thể được thực hiện với nhiều bộ nhớ truy cập, ví dụ họ không nguyên tử. Nó không tạo ra sự khác biệt mà việc viết của bạn được thực hiện một cách nguyên tử với CMPXCHG16B. Đọc cũng phải là nguyên tử hoặc bạn có thể thấy dữ liệu không phù hợp. AFAIK lựa chọn duy nhất của bạn là đọc với CMPXCHG16B. – Timo

+0

Yeh, tôi đã mắc sai lầm khi nghĩ rằng tôi chỉ phải ngăn chặn chuỗi bị gián đoạn giữa lần đọc, nhưng bản thân các hoạt động của xe buýt thực tế vẫn có thể bị xen kẽ. – Eloff

+0

Sử dụng cmpxchg16b trên các lần đọc sẽ làm chậm chúng xuống không thể chấp nhận được. Nhưng bằng cách sử dụng bộ nhớ nhiều hơn 25%, tôi có thể thực hiện một cách tiếp cận theo kiểu seqlock như hashmap của Dmitry Vyukov: http://www.1024cores.net/home/downloads – Eloff

Trả lời

9
typedef struct 
{ 
    unsigned __int128 value; 
} __attribute__ ((aligned (16))) atomic_uint128; 

unsigned __int128 
atomic_read_uint128 (atomic_uint128 *src) 
{ 
    unsigned __int128 result; 
    asm volatile ("xor %%rax, %%rax;" 
       "xor %%rbx, %%rbx;" 
       "xor %%rcx, %%rcx;" 
       "xor %%rdx, %%rdx;" 
       "lock cmpxchg16b %1" : "=A"(result) : "m"(*src) : "rbx", "rcx"); 
    return result; 
} 

Điều đó cần thực hiện thủ thuật. Typedef đảm bảo căn chỉnh chính xác. cmpxchg16b cần dữ liệu được căn chỉnh trên ranh giới 16 byte.

cmpxchg16b sẽ kiểm tra nếu *src chứa số không và viết số không nếu có (nop). Trong cả hai trường hợp, giá trị chính xác sẽ đứng trong RAX: RDX sau đó.

Đoạn mã trên đánh giá một cái gì đó đơn giản như

push %rbx 
xor %rax,%rax 
xor %rbx,%rbx 
xor %rcx,%rcx 
xor %rdx,%rdx 
lock cmpxchg16b (%rdi) 
pop %rbx 
retq 
+0

Vâng, tôi nghĩ rằng đây phải là cách để làm điều đó.Nó xảy ra với tôi bây giờ rằng một tải SSE đơn giản có thể được chia thành hai lần đọc 64bit và rằng cmpxchg16 có khả năng có thể xảy ra giữa các lần đọc. – Eloff

1

Theo tài liệu tham khảo http://siyobik.info/main/reference/instruction/CMPXCHG8B%2FCMPXCHG16B các CMPXCHG16 không phải là theo mặc định nguyên tử nhưng có thể được thực hiện bằng cách sử dụng nguyên tử LOCKhttp://siyobik.info/main/reference/instruction/LOCK

đó có nghĩa là theo mặc định, dữ liệu có thể được thay đổi trong đọc và viết giai đoạn. Khóa làm cho cả đọc và viết nguyên tử.

+0

"Lưu ý rằng CMPXCHG16B yêu cầu toán hạng đích (bộ nhớ) phải được căn chỉnh 16 byte . " – kay

+0

Xin lỗi, vâng tôi có nghĩa là cmpxchg16 với tiền tố khóa. Nhưng khóa không thể được sử dụng với các lệnh SSE. – Eloff

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