Đó là một chút khó khăn để nói những gì "có thể là vấn đề với" (quá mức?) Sử dụng fflush
. Tất cả các loại sự việc có thể trở thành các vấn đề, tùy thuộc vào mục tiêu và cách tiếp cận của bạn. Có lẽ cách tốt hơn để xem đây là mục đích của fflush
là gì.
Điều đầu tiên cần xem xét là fflush
chỉ được xác định trên luồng đầu ra. Một luồng đầu ra thu thập "những thứ cần ghi vào một tệp" vào một bộ đệm lớn (ish), và sau đó ghi bộ đệm đó vào tệp. Điểm thu thập và viết sau này là cải thiện tốc độ/hiệu quả, theo hai cách:
- Trên hệ điều hành hiện đại, có một số hình phạt để vượt qua ranh giới bảo vệ người dùng/hạt nhân (hệ thống phải thay đổi một số thông tin bảo vệ trong CPU, vv). Nếu bạn thực hiện một số lượng lớn các cuộc gọi viết hệ điều hành, bạn sẽ trả tiền phạt đó cho mỗi cuộc gọi. Nếu bạn thu thập, nói, 8192 hoặc để cá nhân viết vào một bộ đệm lớn và sau đó thực hiện một cuộc gọi, bạn loại bỏ hầu hết các chi phí đó.
- Trên nhiều hệ điều hành hiện đại, mỗi cuộc gọi viết OS sẽ cố gắng tối ưu hóa hiệu suất tệp theo một cách nào đó, ví dụ: bằng cách phát hiện bạn đã mở rộng tệp ngắn sang tệp dài hơn và sẽ tốt hơn nếu di chuyển khối đĩa từ điểm A trên đĩa để trỏ B trên đĩa, sao cho dữ liệu dài hơn có thể vừa vặn với nhau. (Trên các hệ điều hành cũ hơn, đây là một bước "chống phân mảnh" riêng biệt mà bạn có thể chạy thủ công. Bạn có thể nghĩ đây là hệ điều hành hiện đại làm việc phân mảnh tức thời, năng động.) Nếu bạn viết 500 byte và 200 khác, và sau đó là 700, v.v., nó sẽ thực hiện rất nhiều công việc này; nhưng nếu bạn thực hiện một cuộc gọi lớn với, 8192 byte, hệ điều hành có thể phân bổ một khối lớn một lần và đặt mọi thứ ở đó và không cần phải chống phân mảnh lại sau.
Vì vậy, những người cung cấp thư viện C và triển khai luồng stdio của bạn thực hiện bất kỳ điều gì phù hợp trên hệ điều hành của bạn để tìm kích thước khối "hợp lý tối ưu" và thu thập tất cả đầu ra vào đoạn đó. (Các con số 4096, 8192, 16384 và 65536 thường, ngày nay, có xu hướng là những cái tốt, nhưng nó thực sự phụ thuộc vào hệ điều hành và đôi khi cũng là hệ thống tệp cơ bản. Lưu ý rằng "lớn hơn" không phải luôn luôn "tốt hơn": dữ liệu luồng theo khối bốn gigabyte tại một thời điểm có thể sẽ hoạt động kém hơn so với thực hiện theo khối 64 Kbytes chẳng hạn.)
Nhưng điều này tạo ra sự cố. Giả sử bạn đang ghi vào một tệp, chẳng hạn như tệp nhật ký có dấu và thông báo ngày và giờ và mã của bạn sẽ tiếp tục ghi vào tệp đó sau, nhưng ngay bây giờ, nó muốn tạm ngưng một lúc và để bộ phân tích nhật ký đọc nội dung hiện tại của tệp nhật ký. Một tùy chọn là sử dụng fclose
để đóng tệp nhật ký, sau đó fopen
để mở lại tệp để thêm dữ liệu sau này.Tuy nhiên, hiệu quả hơn là đẩy mọi thông điệp tường trình đang chờ xử lý vào tệp hệ điều hành cơ sở, nhưng giữ cho tệp mở. Đó là những gì fflush
làm.
Việc đệm cũng tạo ra một vấn đề khác. Giả sử mã của bạn có một số lỗi và đôi khi nó bị lỗi nhưng bạn không chắc liệu mã đó có bị lỗi hay không. Và giả sử bạn đã viết điều gì đó và điều quan trọng là dữ liệu này sẽ được chuyển tới hệ thống tệp cơ bản. Bạn có thể gọi fflush
để đẩy dữ liệu qua hệ điều hành, trước khi gọi mã có khả năng xấu của bạn có thể gặp sự cố. (Đôi khi điều này là tốt để gỡ lỗi.)
Hoặc giả sử bạn đang sử dụng hệ thống giống Unix và có cuộc gọi hệ thống fork
. Cuộc gọi này sao chép toàn bộ không gian người dùng (tạo bản sao của quá trình gốc). Bộ đệm stdio nằm trong không gian người dùng, do đó bản sao có cùng dữ liệu đệm nhưng chưa được viết mà quá trình gốc đã có, tại thời điểm cuộc gọi fork
. Ở đây một lần nữa, một cách để giải quyết vấn đề là sử dụng fflush
để đẩy dữ liệu đệm ra ngay trước khi thực hiện fork
. Nếu mọi thứ đã hết trước fork
, sẽ không có gì để sao chép; bản sao mới sẽ không bao giờ cố gắng ghi dữ liệu đệm, vì nó không còn tồn tại nữa.
Bạn càng thêm nhiều fflush
, bạn càng đánh bại ý tưởng ban đầu về việc thu thập các khối dữ liệu lớn. Tức là, bạn đang cân bằng: các khối lớn hiệu quả hơn, nhưng đang gây ra một số vấn đề khác, vì vậy bạn đưa ra quyết định: "kém hiệu quả ở đây, để giải quyết vấn đề quan trọng hơn hiệu quả đơn thuần". Bạn gọi fflush
.
Đôi khi vấn đề chỉ đơn giản là "gỡ lỗi phần mềm". Trong trường hợp đó, thay vì liên tục gọi fflush
, bạn có thể sử dụng các chức năng như setbuf
và setvbuf
để thay đổi hành vi đệm của luồng stdio. Điều này thuận tiện hơn (ít hoặc thậm chí không cần thay đổi mã — bạn có thể kiểm soát cuộc gọi đệm bằng cờ) hơn là thêm nhiều cuộc gọi fflush
, do đó có thể được coi là "sự cố khi sử dụng (hoặc sử dụng quá mức)) của fflush
".
khi bạn sử dụng 'printf()' mà không cần bất kỳ dòng sản phẩm mới, nó sẽ có thể sẽ không in ngay lập tức. nếu bạn biết chương trình của bạn có thể bị hỏng bất kỳ giây nào, bạn có thể sử dụng 'fflush()' (hoặc newlines ...). Tôi không nghĩ rằng đây là cách sử dụng phổ biến mặc dù. – Elazar
Chỉ có vấn đề tôi có thể nghĩ là làm việc đó quá thường xuyên là xấu cho hiệu suất. Ngoài ra, bạn nên biết rằng việc đóng một tập tin hoặc chương trình chấm dứt ngụ ý một tuôn ra tự động. Một chương trình chạy ngắn sẽ hiếm khi cần gọi 'fflush()' một cách rõ ràng. – thejh
Toàn bộ mục đích của 'stdio' là cung cấp đệm bên ứng dụng cho các cuộc gọi hệ thống' read() 'và' write() '. Bất cứ lúc nào bạn có bộ đệm bạn cần một hoạt động tuôn ra. 'Vấn đề' có thể nhận dạng duy nhất với nó là quên sử dụng nó khi bạn cần, hoặc có thể lạm dụng nó, ví dụ: bên trong vòng thay vì ở cuối vòng lặp. – EJP