GCC cung cấp một bộ tốt đẹp của built-in functions cho các hoạt động nguyên tử. Và đang sử dụng hệ điều hành MacOS hoặc iOS, ngay cả Apple cũng cung cấp nice set of atomic functions. Tuy nhiên, tất cả các chức năng này thực hiện một thao tác, ví dụ: một phép cộng/trừ, một phép toán logic (AND/OR/XOR) hoặc so sánh và đặt/so sánh và trao đổi. Những gì tôi đang tìm kiếm là cách để chỉ định/đọc một cách nguyên tắc giá trị int
, như:Đọc/ghi nguyên tử giá trị int w/o hoạt động bổ sung trên giá trị int của chính nó
int a;
/* ... */
a = someVariable;
Đó là tất cả. a
sẽ được đọc bởi một chuỗi khác và điều quan trọng là a
có giá trị cũ hoặc giá trị mới của nó. Thật không may là tiêu chuẩn C không đảm bảo rằng việc gán hoặc đọc một giá trị là một hoạt động nguyên tử. Tôi nhớ rằng tôi đã từng đọc ở đâu đó, việc viết hoặc đọc một giá trị cho biến số int
được đảm bảo là nguyên tử trong GCC (bất kể kích thước của int) nhưng tôi đã tìm kiếm ở khắp mọi nơi trên trang chủ GCC và tôi không thể tìm thấy câu lệnh này nữa (có thể nó đã bị xóa).
Tôi không thể sử dụng sig_atomic_t
vì sig_atomic_t không có kích thước đảm bảo và kích thước cũng có thể có kích thước khác với int
.
Vì chỉ có một chủ đề sẽ bao giờ "viết" một giá trị cho a
, trong khi cả hai chủ đề sẽ "đọc" các giá trị hiện tại của a
, tôi không cần phải thực hiện các hoạt động bản thân một cách nguyên tử, ví dụ:
/* thread 1 */
someVariable = atomicRead(a);
/* Do something with someVariable, non-atomic, when done */
atomicWrite(a, someVariable);
/* thread 2 */
someVariable = atomicRead(a);
/* Do something with someVariable, but never write to a */
Nếu cả hai luồng sẽ ghi vào a
thì tất cả các thao tác sẽ phải là nguyên tử, nhưng theo cách đó, điều này chỉ có thể lãng phí thời gian CPU; và chúng tôi rất ít tài nguyên CPU trong dự án của mình. Cho đến nay chúng tôi sử dụng một mutex xung quanh hoạt động đọc/ghi của a
và mặc dù mutex được giữ trong một khoảng thời gian nhỏ như vậy, điều này đã gây ra sự cố (một trong các chủ đề là chuỗi thời gian thực và chặn trên mutex. các ràng buộc thời gian thực của nó, điều này khá tệ).
Tất nhiên tôi có thể sử dụng __sync_fetch_and_add
để đọc biến (và chỉ cần thêm "0" vào nó, để không sửa đổi giá trị của nó) và để viết sử dụng __sync_val_compare_and_swap
để viết nó (như tôi biết giá trị cũ của nó điều đó sẽ đảm bảo giá trị luôn được trao đổi), nhưng điều này sẽ không làm tăng thêm chi phí không cần thiết?
Làm cách nào để biết nó không rộng hơn một từ? Đi theo ISO-C-99, "loại int" nào được định nghĩa là luôn chính xác bằng từ? Theo như tôi có thể nói điều này là không đảm bảo cho bất kỳ loại int; ví dụ. trên một bộ điều khiển vi 8 bit, một int sẽ vẫn là 16 bit, mặc dù kích thước từ thực tế là 8 bit. – Mecki
Một 'sig_atomic_t' nên làm, ngay cả khi nó có nghĩa là cho một cái gì đó hoàn toàn khác nhau (xử lý tín hiệu). Dù sao, tôi không nghĩ rằng backends vi điều khiển thậm chí thực hiện '__sync_fetch_and_add', vì vậy nếu bạn đưa họ vào tài khoản tất cả các cược được tắt. –
'intptr_t' và' uintptr_t' typedefs được đảm bảo là thích hợp để lưu trữ một con trỏ, mà thường là rộng như từ máy. –