2010-05-23 23 views
9

Một câu hỏi nhanh tôi đã tự hỏi về một thời gian; CPU có gán các giá trị nguyên tử không, hoặc là bit từng chút một (ví dụ như một số nguyên 32 bit).
Nếu nó từng chút một, một chuỗi khác có thể truy cập vào vị trí chính xác này có được "phần" của giá trị được gán không?CPU có gán giá trị nguyên tử cho bộ nhớ không?

Hãy nghĩ về điều này:
Tôi có hai chủ đề và một biến "unsigned int" được chia sẻ (gọi nó là "g_uiVal").
Cả hai luồng đều lặp lại.
Bật đang in "g_uiVal" với printf ("% u \ n", g_uiVal).
Thứ hai chỉ tăng số này.
Chủ đề in có bao giờ in một cái gì đó hoàn toàn không hoặc một phần của giá trị "g_uiVal" không?

Trong mã:

unsigned int g_uiVal; 

void thread_writer() 
{ 
g_uiVal++; 
} 
void thread_reader() 
{ 
while(1) 
    printf("%u\n", g_uiVal); 
} 

Trả lời

5

Phụ thuộc vào độ rộng bus của CPU và bộ nhớ. Trong bối cảnh PC, với bất kỳ thứ gì khác ngoài một CPU thực sự cổ đại, truy cập tới 32 bit truy cập là nguyên tử; Truy cập 64 bit có thể có hoặc không. Trong không gian nhúng, nhiều CPU (nhiều nhất?) Có chiều rộng 32 bit và không có điều khoản cho bất kỳ thứ gì rộng hơn, do đó, int64_t của bạn được đảm bảo không nguyên tử.

+0

Có thể truy cập vào các giá trị 32 bit qua các dòng bộ nhớ cache trong những ngày này không? –

+0

@Lasse: Nhiều bộ vi xử lý dành cho máy tính để bàn hiện đại cho phép đọc và viết không được ký hiệu, nhưng ở mức phạt đáng kể về hiệu suất. CPU cũ hơn hoặc nhỏ hơn (ví dụ: các thiết bị nhúng) có xu hướng không. Trong một thời gian, điều này đã được phân chia giữa các bộ vi xử lý CISC (có xu hướng hỗ trợ đọc và viết chưa được ký) và bộ xử lý RISC (không), nhưng sự khác biệt đang làm mờ ở đây. – leander

+0

8, 16 và 32 bit vi điều khiển là tất cả phổ biến. Trên một AVR (với 8 bit tải và các cửa hàng) có thể có một ISR (gián đoạn dịch vụ thường xuyên) hoặc thread khác (nếu bạn đang chạy một hệ điều hành đa nhiệm có thể được ưu tiên) viết một phần của biến (hoặc chỉ đọc một phần của thay đổi chuỗi đã tạo trước đó). – nategoose

3

Tôi tin rằng câu trả lời đúng duy nhất là "nó phụ thuộc". Về những gì bạn có thể yêu cầu?

Tốt cho những người mới bắt đầu có CPU. Nhưng cũng có một số CPU là nguyên tử để viết các giá trị độ rộng từ, nhưng chỉ khi căn chỉnh. Nó thực sự không phải là thứ bạn có thể đảm bảo ở cấp độ ngôn ngữ C.

Nhiều trình biên dịch cung cấp "nội tại" để phát ra các hoạt động nguyên tử chính xác. Đây là những phần mở rộng hoạt động giống như các hàm, nhưng phát ra mã đúng cho kiến ​​trúc đích của bạn để có được các hoạt động nguyên tử cần thiết. Ví dụ: http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html

0

Để thêm vào những gì đã được nói cho đến nay - một mối quan tâm tiềm năng khác là lưu vào bộ nhớ cache. Các CPU có khuynh hướng làm việc với bộ nhớ cache cục bộ (trên khuôn mặt) mà có thể hoặc không thể được xả ngay lập tức trở lại bộ nhớ chính. Nếu hộp có nhiều hơn một CPU, có thể một CPU khác sẽ không thấy các thay đổi trong một thời gian sau khi CPU sửa đổi tạo ra chúng - trừ khi có một số lệnh đồng bộ thông báo cho tất cả các CPU mà chúng cần đồng bộ hóa bộ nhớ cache của chúng. Như bạn có thể tưởng tượng việc đồng bộ hóa đó có thể làm chậm quá trình xử lý.

+0

Nhưng trong trường hợp này, vì không có sự đồng bộ giữa người tiêu dùng và nhà sản xuất nên nó không thực sự thay đổi hành vi. Chắc chắn, người tiêu dùng có thể đọc một giá trị cũ, nhưng nó sẽ không thể cho biết nếu nó là do không đồng bộ trên bộ nhớ cache hoặc chỉ lập kế hoạch. Những gì tôi nhận được là người tiêu dùng sẽ không bao giờ đọc một phần giá trị bằng văn bản do bộ nhớ cache không đồng bộ –

+0

Tất cả phụ thuộc vào những gì được mong đợi. Nếu ý định là để tạo ra các giá trị duy nhất - tốt, vấn đề này có thể giới thiệu các bản sao – mfeingold

0

Đừng quên rằng trình biên dịch giả định chuỗi đơn khi tối ưu hóa và toàn bộ điều này có thể biến mất.

+0

mặc dù nó là một biến toàn cục rõ ràng được sử dụng trong các chức năng khác? Tôi nghi ngờ bất kỳ trình biên dịch sẽ được * rằng * thô lỗ :) –

+0

@Isak Savo: tĩnh (non-extern) biến toàn cầu không biến động? chắc chắn, tại sao không? Đánh dấu tất cả các biến được sử dụng để kiểm soát đồng thời là dễ bay hơi, điều này ngăn cản tối ưu hóa trình biên dịch liên quan đến các biến này. – liori

+0

@liori: Nhưng ngay cả trong một ứng dụng đơn luồng, đó là mã hoàn toàn hợp lệ.Kiến trúc xấu sang một bên, không có gì sai khi có một hàm sửa đổi các biến toàn cầu mà không sử dụng kết quả của chính chúng. –

1

Bạn đã nói "từng bit một" trong câu hỏi của mình. Tôi không nghĩ rằng bất kỳ kiến ​​trúc nào hoạt động một chút tại một thời điểm, ngoại trừ một số giao thức giao thức nối tiếp chuyên biệt. Đọc/ghi bộ nhớ tiêu chuẩn được thực hiện với độ chi tiết 8, 16, 32 hoặc 64 bit. Vì vậy, nó có thể hoạt động trong ví dụ của bạn là nguyên tử.

Tuy nhiên, câu trả lời phụ thuộc nhiều vào nền tảng.

  • Tùy thuộc vào khả năng của CPU. Phần cứng có thể thực hiện hoạt động 32 bit nguyên tử không? Dưới đây là gợi ý: Nếu biến số bạn đang làm việc lớn hơn so với kích thước đăng ký gốc (ví dụ: int 64 bit trên hệ thống 32 bit), thì chắc chắn KHÔNG phải là nguyên tử.
  • Phụ thuộc vào cách trình biên dịch tạo mã máy. Nó có thể đã biến biến 32 bit của bạn truy cập vào bộ nhớ 8-bit 4x lần đọc.
  • Sẽ rất phức tạp nếu địa chỉ của những gì bạn đang truy cập không được căn chỉnh qua ranh giới tự nhiên của một máy là ranh giới . Bạn có thể gặp lỗi bộ nhớ cache hoặc lỗi trang .

RẤT NHIỀU R thatNG bạn sẽ thấy giá trị bị hỏng hoặc không mong muốn bằng cách sử dụng ví dụ mã mà bạn đã đăng.

Nền tảng của bạn có thể cung cấp một số phương pháp thực hiện các hoạt động nguyên tử. Trong trường hợp của một nền tảng Windows, nó là thông qua các Interlocked functions. Trong trường hợp của Linux/Unix, hãy xem atomic_t type.

0

POSIX định nghĩa loại đặc biệt sig_atomic_t mà guarentees viết cho nó là nguyên tử đối với tín hiệu, mà sẽ làm cho nó cũng nguyên tử từ quan điểm của các chủ đề khác như bạn muốn. Họ không xác định cụ thể một loại cross-thread nguyên tử như thế này, kể từ khi giao tiếp thread dự kiến ​​sẽ được trung gian bởi mutexes hoặc nguyên thủy khác.

0

Xem xét các bộ vi xử lý hiện đại (và bỏ qua bộ vi điều khiển), phép gán 32 bit là nguyên tử, chứ không phải bit-by-bit.

Tuy nhiên, bây giờ hoàn toàn tắt chủ đề câu hỏi của bạn ... chủ đề in vẫn có thể in thứ gì đó không được mong đợi vì thiếu đồng bộ trong ví dụ này, tất nhiên, do hướng dẫn sắp xếp lại và nhiều lõi với nhau bản sao riêng của g_uiVal trong bộ nhớ cache của họ.

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