2012-05-08 43 views
14

Trên máy đa lõi x86, hãy nói một chuỗi thực hiện trên lõi 1 tăng một số nguyên a tại cùng một chuỗi thời gian trên lõi 2 cũng tăng nó. Giả sử giá trị ban đầu là a là 0, cuối cùng có phải là 2 không? Hoặc nó có thể có một số giá trị khác? Giả sử rằng a được khai báo là volatile và chúng tôi không sử dụng các biến nguyên tử (chẳng hạn như nguyên tử <> của C++ và được xây dựng trong các hoạt động nguyên tử trong gcc).Có phải tăng số nguyên nguyên tử trong x86 không?

Nếu giá trị a thực sự sẽ luôn là 2 trong trường hợp như vậy, điều đó có nghĩa là long int trong x86-64 cũng sẽ có cùng một thuộc tính, tức là a sẽ luôn là 2 cuối cùng?

+4

trừ khi bạn đang sử dụng loại nguyên tử đặc biệt, số gia tăng thường là ba hoạt động riêng biệt. Tải, tăng, sau đó lưu trữ. –

+4

'volatile' không cung cấp cho bạn quyền truy cập nguyên tử. –

+3

@CatPlusPlus là tên của bạn hoạt động nguyên tử? : P – MByD

Trả lời

24

Lệnh máy bộ nhớ gia tăng trên X86 chỉ là nguyên tử nếu bạn sử dụng nó với tiền tố LOCK.

x ++ trong C và C++ không có hành vi nguyên tử. Nếu bạn tăng số mở khóa, do các bộ xử lý đang đọc và ghi X, nếu hai bộ xử lý riêng biệt cố gắng tăng, bạn có thể kết thúc chỉ với một gia số hoặc cả hai được nhìn thấy (bộ xử lý thứ hai có thể đã đọc giá trị ban đầu, tăng dần và viết lại sau khi lần đầu tiên ghi lại kết quả của nó). Tôi tin rằng C++ 11 cung cấp gia số nguyên tử, và hầu hết các trình biên dịch của nhà cung cấp có cách thức thành ngữ để làm tăng số nguyên tử của một số kiểu số nguyên nhất định (thường là int và long); xem hướng dẫn tham khảo trình biên dịch của bạn.

Nếu bạn muốn tăng "giá trị lớn" (ví dụ, số nguyên bội), bạn cần làm như vậy bằng cách sử dụng một số cơ chế khóa tiêu chuẩn như semaphore.

Lưu ý rằng bạn cần phải lo lắng về nguyên tử cũng đọc. Trên x86, đọc một giá trị 32 hoặc 64 bit xảy ra là nguyên tử nếu nó được liên kết từ 64 bit. Điều đó sẽ không đúng với "giá trị lớn"; một lần nữa bạn sẽ cần một số khóa tiêu chuẩn.

+0

Tiền tố LOCK có đảm bảo các hàng rào cần thiết không? (Tôi nghĩ như vậy, nhưng tôi không chắc chắn.) –

+0

Có. .......... –

4

Không đảm bảo. Bạn có thể sử dụng lệnh lock xadd để đạt được hiệu quả tương tự hoặc sử dụng C++ std::atomic hoặc sử dụng #pragma omp atomic hoặc bất kỳ số giải pháp đồng thời nào khác đã được viết để giúp bạn khắc phục sự cố khi phát minh lại bánh xe.

7

Dưới đây là một bằng chứng nó không phải là nguyên tử trong một thực hiện cụ thể (gcc), Như bạn có thể nhìn thấy (?), Gcc tạo ra mã mà

  1. tải giá trị từ bộ nhớ vào một thanh ghi
  2. gia nội dung của sổ đăng ký
  3. lưu sổ đăng ký trở lại bộ nhớ.

Điều này rất xa so với nguyên tử.

$ cat t.c 
volatile int a; 

void func(void) 
{ 
    a++; 
} 
[19:51:52 0 ~] $ gcc -O2 -c t.c 
[19:51:55 0 ~] $ objdump -d t.o 

t.o:  file format elf32-i386 


Disassembly of section .text: 

00000000 <func>: 
    0: a1 00 00 00 00   mov 0x0,%eax 
    5: 83 c0 01    add $0x1,%eax 
    8: a3 00 00 00 00   mov %eax,0x0 
    d: c3      ret 

Đừng để bị lừa bởi các 0x0 trong hướng dẫn mov, có chỗ cho 4 byte ở đó, và các mối liên kết sẽ điền vào kết quả các địa chỉ bộ nhớ cho a có khi đối tượng tập tin này được liên kết.

+0

Thật buồn cười, bạn chỉ thực sự tải/thêm/lưu trữ riêng biệt khi 'a' là' dễ bay hơi', nếu không gcc sẽ sử dụng tính năng đọc-sửa-ghi (trừ khi điều chỉnh cho [i586 (pentium))] (https://godbolt.org/g/3K8zfu)). Tất nhiên, nếu mã xung quanh sử dụng giá trị của num ++, nó sẽ rất có thể được thực hiện với các hướng dẫn riêng biệt để lại kết quả trong sổ đăng ký. Tôi đã đề cập đến điều này trong câu trả lời của tôi về [một câu hỏi không phải là 'biến thể ') (http://stackoverflow.com/questions/39393850/can-num-be-atomic-for-int-num/39396999#39396999). –

+0

@PaterCordes Không có biến động, gcc có thể tạo ra một lệnh 'addl' duy nhất, mặc dù đó không phải là nguyên tử trừ khi bạn cũng sử dụng tiền tố 'lock'. – nos

+0

: P Liên kết thứ hai trong bình luận trước của tôi là câu trả lời của tôi giải thích chính xác (về giao thức MESI, vv) tại sao 'addl $ 1, num' không phải là nguyên tử (ngoại trừ hệ thống uniprocessor nếu chúng ta không bao gồm các nhà quan sát DMA) và tại sao nó lại có 'khóa'. –

7

Vì không ai có thể trả lời câu hỏi thực tế của bạn và thay vào đó được hiển thị cho bạn làm thế nào để làm điều đó theo một cách mà luôn luôn làm việc:

Chủ đề 1 tải giá trị từ 0

Chủ đề 2 tải giá trị từ 0

chủ đề 1 gia số một cửa hàng 1

chủ đề 2 increments bản sao đăng ký tại địa phương của mình có giá trị và các cửa hàng 1.

Như bạn có thể thấy kết quả cuối cùng là một giá trị bằng 1 và không phải 2. Nó sẽ không luôn luôn là 2 ở cuối.

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