Các lập trình viên C thường lấy biến động để có nghĩa là biến có thể được thay đổi bên ngoài luồng thực thi hiện tại; kết quả là, đôi khi họ bị cám dỗ sử dụng nó trong mã hạt nhân khi các cấu trúc dữ liệu được chia sẻ đang được sử dụng. Nói cách khác, chúng đã được biết là coi các loại dễ bay hơi như một loại biến nguyên tử dễ dàng, mà chúng không phải là. Việc sử dụng biến động trong mã kernel hầu như không bao giờ đúng; tài liệu này mô tả lý do tại sao.
Điểm mấu chốt để hiểu về sự biến động là mục đích của nó là triệt tiêu tối ưu hóa, điều gần như không bao giờ là điều người ta thực sự muốn làm. Trong kernel, người ta phải bảo vệ các cấu trúc dữ liệu được chia sẻ trước sự truy cập đồng thời không mong muốn, đây là một nhiệm vụ khác. Quá trình bảo vệ chống lại sự tương tranh không mong muốn cũng sẽ tránh được hầu hết các vấn đề liên quan đến tối ưu hóa theo cách hiệu quả hơn.
Giống như dễ bay hơi, các nguyên hàm hạt nhân giúp truy cập đồng thời vào dữ liệu an toàn (spinlocks, mutexes, rào cản bộ nhớ, v.v.) được thiết kế để ngăn chặn tối ưu hóa không mong muốn. Nếu chúng đang được sử dụng đúng cách, sẽ không có nhu cầu sử dụng dễ bay hơi. Nếu không ổn định vẫn cần thiết, gần như chắc chắn có một lỗi trong mã ở đâu đó. Trong mã hạt nhân được viết đúng, dễ bay hơi chỉ có thể phục vụ để làm chậm mọi thứ.
Hãy xem xét một khối mã hạt nhân điển hình:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
Nếu tất cả các mã tuân theo các quy tắc khóa, giá trị của shared_data không thể thay đổi bất ngờ trong khi giữ khóa_lock. Bất kỳ mã nào khác có thể muốn phát với dữ liệu đó sẽ chờ trên khóa. Các nguyên thủy spinlock hoạt động như các rào cản bộ nhớ - chúng được viết rõ ràng để làm như vậy - có nghĩa là các truy cập dữ liệu sẽ không được tối ưu hóa trên chúng. Vì vậy, trình biên dịch có thể nghĩ rằng nó biết những gì sẽ có trong shared_data, nhưng lệnh gọi spin_lock (), vì nó hoạt động như một rào cản bộ nhớ, sẽ buộc nó quên bất cứ điều gì nó biết. Sẽ không có vấn đề tối ưu hóa với việc truy cập vào dữ liệu đó.
Nếu shared_data được khai báo là không ổn định, việc khóa vẫn sẽ là cần thiết. Nhưng trình biên dịch cũng sẽ bị ngăn chặn tối ưu hóa quyền truy cập vào shared_data trong phần quan trọng, khi chúng tôi biết rằng không ai khác có thể làm việc với nó. Trong khi khóa được giữ, shared_data không biến động. Khi xử lý dữ liệu chia sẻ, khóa thích hợp làm cho biến động không cần thiết - và có thể gây hại.
Lớp lưu trữ dễ bay hơi ban đầu có nghĩa là cho các thanh ghi I / O được ánh xạ bộ nhớ. Trong kernel, các truy cập đăng ký cũng nên được bảo vệ bởi các khóa, nhưng người ta cũng không muốn trình biên dịch "tối ưu hóa" các truy cập đăng ký trong một phần quan trọng. Nhưng, trong nhân, việc truy cập bộ nhớ I / O luôn được thực hiện thông qua các hàm truy cập; truy cập bộ nhớ I / O trực tiếp thông qua con trỏ được tán thành và không hoạt động trên tất cả các kiến trúc. Những người truy cập được viết để ngăn chặn tối ưu hóa không mong muốn, vì vậy, một lần nữa, biến động là không cần thiết.
Một tình huống khác mà người ta có thể muốn sử dụng dễ bay hơi là khi bộ xử lý đang bận chờ đợi giá trị của một biến. Cách đúng đắn để thực hiện chờ đợi bận rộn là:
while (my_variable != what_i_want)
cpu_relax();
Cuộc gọi cpu_relax () có thể giảm mức tiêu thụ năng lượng của CPU hoặc mang lại bộ xử lý sinh đôi siêu phân luồng; nó cũng xảy ra để phục vụ như một rào cản bộ nhớ, vì vậy, một lần nữa, biến động là không cần thiết. Tất nhiên, bận rộn chờ đợi nói chung là một hành động chống đối xã hội bắt đầu.
Vẫn còn một vài tình huống hiếm hoi mà sự biến động có ý nghĩa trong nhân:
Các hàm truy cập được đề cập ở trên có thể sử dụng không ổn định trên các kiến trúc nơi truy cập bộ nhớ I / O trực tiếp không hoạt động. Về cơ bản, mỗi cuộc gọi của người truy cập trở thành một phần quan trọng nhỏ và đảm bảo rằng việc truy cập diễn ra như mong đợi của lập trình viên.
Mã lắp ráp nội tuyến thay đổi bộ nhớ, nhưng không có tác dụng phụ có thể nhìn thấy khác, có nguy cơ bị GCC xóa. Thêm từ khóa dễ bay hơi vào các câu lệnh asm sẽ ngăn chặn việc loại bỏ này.
Biến jiffies đặc biệt ở chỗ nó có thể có giá trị khác nhau mỗi lần được tham chiếu, nhưng nó có thể được đọc mà không cần khóa đặc biệt. Vì vậy, jiffies có thể không ổn định, nhưng việc bổ sung các biến khác của loại này được tán thành mạnh mẽ. Jiffies được coi là một vấn đề "di sản ngu ngốc" (lời của Linus) trong vấn đề này; sửa chữa nó sẽ là rắc rối nhiều hơn nó là giá trị.
Con trỏ tới cấu trúc dữ liệu trong bộ nhớ kết hợp có thể được sửa đổi bởi các thiết bị I / O đôi khi có thể biến động một cách hợp pháp. Bộ đệm vòng được sử dụng bởi bộ điều hợp mạng, trong đó bộ điều hợp thay đổi con trỏ để chỉ ra mô tả nào đã được xử lý, là một ví dụ về loại tình huống này.
Đối với hầu hết các mã, không có bất kỳ biện minh nào ở trên cho việc áp dụng dễ bay hơi. Do đó, việc sử dụng dễ bay hơi có thể được coi là một lỗi và sẽ mang lại sự xem xét kỹ lưỡng hơn cho mã. Các nhà phát triển bị cám dỗ sử dụng biến động nên lùi lại một bước và suy nghĩ về những gì họ đang thực sự cố gắng thực hiện.