2009-01-22 52 views
18

Số CreateFile của Win32 có FILE_FLAG_DELETE_ON_CLOSE, nhưng tôi đang sử dụng Linux.Xóa tệp được đảm bảo khi chấm dứt chương trình (C/C++)

Tôi muốn mở tệp tạm thời sẽ luôn bị xóa khi chấm dứt chương trình. Tôi có thể hiểu rằng trong trường hợp của một vụ tai nạn chương trình nó có thể không thực tế để đảm bảo điều này, nhưng trong bất kỳ trường hợp nào khác tôi muốn nó hoạt động.

Tôi biết về RAII. Tôi biết về tín hiệu. Tôi biết về atexit(3). Tôi biết tôi có thể mở tệp và xóa tệp đó ngay lập tức và tệp sẽ vẫn có thể truy cập được cho đến khi trình mô tả tệp được đóng (thậm chí có thể xử lý sự cố). Không ai trong số này có vẻ như một giải pháp hoàn chỉnh và đơn giản:

  1. RAII: ở đó, thực hiện điều đó: Tôi có một đối tượng có destructor xóa tệp, nhưng hủy không được gọi nếu chương trình bị chấm dứt bởi tín hiệu.
  2. Tín hiệu
  3. : Tôi đang viết thư viện cấp thấp, điều này khiến cho việc đăng ký trình xử lý tín hiệu trở thành một đề xuất khó khăn. Ví dụ, nếu ứng dụng sử dụng chính các tín hiệu thì sao? Tôi không muốn bước lên bất kỳ ngón chân nào. Tôi có thể xem xét một số sử dụng thông minh của sigaction(2) để đối phó ... nhưng chưa đưa đủ suy nghĩ vào khả năng này.
  4. atexit(3): dường như vô dụng, vì nó không được gọi trong khi chấm dứt bất thường (ví dụ: thông qua tín hiệu).
  5. preemptive unlink(2): điều này khá tốt ngoại trừ việc tôi cần tệp để hiển thị trong hệ thống tệp (nếu không hệ thống sẽ khó giám sát/khắc phục sự cố).

Bạn sẽ làm gì ở đây?

giải thích thêm

tôi elided một chi tiết trong bài viết ban đầu của tôi mà tôi bây giờ nhận ra tôi nên tôi đã bao gồm. "Tệp" trong trường hợp này không phải là một tệp bình thường, mà là một Hàng đợi Thông báo POSIX. Tôi tạo nó qua mq_open(). Nó có thể được đóng lại thông qua mq_close() hoặc close() (trước đây là một bí danh cho sau này trên hệ thống của tôi). Nó có thể được gỡ bỏ khỏi hệ thống thông qua mq_unlink(). Tất cả điều này làm cho nó tương tự như một tệp thông thường, ngoại trừ mà tôi không thể chọn thư mục chứa tệp. Điều này làm cho câu trả lời phổ biến nhất hiện nay (đặt các tập tin trong /tmp) unworkable, bởi vì "tập tin" được tạo ra bởi hệ thống trong một hệ thống tập tin ảo với công suất rất hạn chế. (Tôi đã gắn hệ thống tệp ảo trong /dev/mqueue, theo ví dụ trong man mq_overview).

Điều này cũng giải thích tại sao tôi cần tên để hiển thị (làm cho cách tiếp cận ngay lập tức-hủy liên kết không thể thực hiện được): "tệp" phải được chia sẻ giữa hai hoặc nhiều quy trình.

+0

Đây là mục 4 (giữ tên có thể truy cập được) khiến nó trở nên khó khăn. –

+0

Mỗi khi một chi tiết quan trọng bị bỏ đi, câu trả lời sẽ trở nên tồi tệ. Bạn sẽ biết trong thời gian tới. –

Trả lời

7

Yêu cầu rằng tên vẫn hiển thị trong khi quá trình đang chạy khiến việc này khó đạt được. Bạn có thể xem lại yêu cầu đó không?

Nếu không, thì có thể không phải là giải pháp hoàn hảo. Tôi sẽ xem xét kết hợp một chiến lược xử lý tín hiệu với những gì Kamil Kisiel gợi ý. Bạn có thể theo dõi các trình xử lý tín hiệu được cài đặt trước khi cài đặt các trình xử lý tín hiệu của mình. Nếu trình xử lý mặc định là SIG_IGN, bạn sẽ không thường cài đặt trình xử lý của riêng mình; nếu đó là SIG_DFL, bạn sẽ nhớ điều đó; nếu nó là cái gì khác - một trình xử lý tín hiệu do người dùng định nghĩa - bạn sẽ nhớ con trỏ đó và cài đặt con trỏ của riêng mình. Khi xử lý của bạn đã được gọi, bạn sẽ làm bất cứ điều gì bạn cần làm, và sau đó gọi xử lý nhớ, do đó chuỗi xử lý. Bạn cũng sẽ cài đặt một trình xử lý atexit(). Bạn cũng sẽ ghi lại rằng bạn làm điều này, và các tín hiệu mà bạn làm điều đó.

Lưu ý rằng xử lý tín hiệu là một chiến lược không hoàn hảo; SIGKILL không thể bị bắt, và trình xử lý atexit() sẽ không được gọi, và tập tin sẽ bị bỏ lại.

Đề xuất của David Segond - một daemon tên tệp tạm thời - thật thú vị. Đối với các quy trình đơn giản, nó là đủ; nếu quá trình yêu cầu dĩa tạm thời và mong đợi đứa trẻ sở hữu tệp sau đó (và thoát) thì daemon có vấn đề phát hiện khi quá trình cuối cùng sử dụng nó chết - bởi vì nó không tự động biết các tiến trình đã mở nó.

+1

Tôi không tin rằng tôi có thể xóa yêu cầu hiển thị tên tệp. Tôi đã thêm "Giải thích thêm" cho câu hỏi ban đầu giải thích rằng đây không phải là một tệp thông thường và nó sống ở một vị trí cố định với công suất rất hạn chế. Tôi nghĩ rằng tôi cần phải có các tập tin có thể nhìn thấy để theo dõi. –

+0

Tất nhiên, nếu có một số cách khác để đạt được mục tiêu của tôi mà không có yêu cầu hiển thị tên, tôi có thể làm điều đó thay thế. Về cơ bản tôi cần một cách phong nha để giữ cho các tập tin từ chồng chất lên, bởi vì họ tiêu thụ một nguồn lực rất hạn chế (tưởng tượng một hệ thống tập tin với dung lượng 16MB và ~ 200KB tập tin). –

+0

Ồ, và để tôi không quên, những cái tên cần được duy trì trong suốt quá trình hoạt động bình thường vì chúng được chia sẻ giữa các chương trình. Tôi không thể bỏ liên kết chúng ngay lập tức sau khi tạo ra chúng - điều đó sẽ khiến chúng vô dụng. Tôi nên có được rõ ràng về điều đó ban đầu. –

6

Nếu bạn chỉ tạo một tệp tạm thời, chỉ cần tạo tệp đó trong /tmp hoặc thư mục con của chúng. Sau đó, thực hiện một nỗ lực tốt nhất để xóa nó khi thực hiện thông qua atexit(3) hoặc tương tự. Miễn là bạn sử dụng tên duy nhất được chọn thông qua mkstemp(3) hoặc tương tự ngay cả khi nó không bị xóa do một sự cố chương trình, bạn không có nguy cơ đọc lại nó trong lần chạy tiếp theo hoặc các điều kiện khác.

Tại thời điểm đó, đó chỉ là vấn đề cấp hệ thống giữ an toàn cho /tmp. Hầu hết các bản phân phối sẽ xóa nó khi khởi động hoặc tắt máy, hoặc chạy cronjob thông thường để xóa các tập tin cũ.

+0

Đây không phải lỗi của bạn, nhưng tôi không thể sử dụng giải pháp này. Vui lòng xem "Giải thích thêm" của tôi trong câu hỏi. Tôi không thể chọn đường dẫn cho tập tin, và hệ thống tập tin mà nó cư trú có kích thước rất hạn chế. Nếu tôi không còn lựa chọn nào khác, tôi cũng có thể quét nó với cron-một giải pháp xấu. –

3

Trước đây, tôi đã tạo "trình quản lý tệp tạm thời" để theo dõi các tệp tạm thời.

Một người sẽ yêu cầu tên tệp tạm thời từ người quản lý và tên này đã được đăng ký.

Khi bạn không cần tên tệp tạm thời nữa, bạn thông báo cho người quản lý và tên tệp không được đăng ký.

Khi nhận được tín hiệu kết thúc, tất cả các tệp tạm thời đã đăng ký đã bị hủy.

Tên tệp tạm thời là UUID dựa trên để tránh va chạm.

+0

Phức tạp, nhưng rõ ràng nó hoạt động - gấp đôi vì vậy nếu người quản lý tệp tạm thời có cách để phát hiện xem quá trình yêu cầu tệp tạm thời vẫn tồn tại. Có một chút khó khăn nếu dĩa quá trình đó; gấp đôi như vậy nếu cha mẹ thoát. –

+0

Bạn có thể thêm một yêu cầu rằng khi một quy trình dĩa, cha mẹ phải thông báo cho người quản lý của pid của quá trình con. Điều này cũng cho phép sự linh hoạt của các loại khác của quá trình liên comm. được sử dụng để chuyển tên tệp của tệp tmp xung quanh. – KeithB

+0

David, câu trả lời của bạn có vẻ như là "người quản lý" này hoạt động như một mô-đun trong cùng một quy trình. Nhận xét của Jonathan làm cho nó nghe như thể nó sẽ là một quá trình riêng biệt. Tôi có thể thấy cách nó có thể hoạt động như một quá trình riêng biệt, chắc chắn, nhưng bạn có cho rằng nó có thể đang trong quá trình không? Nếu vậy tôi không thấy nhiều giá trị .... –

0

Bạn có thể có ngã ba quy trình sau khi tạo tệp, sau đó đợi trẻ đóng, sau đó phụ huynh có thể hủy liên kết tệp và thoát.

4

Có lẽ ai đó đã đề xuất điều này, nhưng tôi không thể phát hiện ra, với tất cả các yêu cầu của bạn, điều tốt nhất tôi có thể nghĩ là đặt tên tệp bằng cách nào đó được truyền đạt tới quy trình gốc, chẳng hạn như tập lệnh khởi động, sẽ làm sạch sau khi quá trình chết, đã không làm như vậy. Điều này có lẽ chủ yếu được biết đến như một cơ quan giám sát, nhưng sau đó với trường hợp sử dụng phổ biến hơn được thêm vào để giết và/hoặc khởi động lại quá trình khi nó bằng cách nào đó thất bại.

Nếu quá trình cha mẹ của bạn chết, bạn hầu như không may mắn, nhưng hầu hết các môi trường tập lệnh đều khá mạnh và hiếm khi chết trừ khi tập lệnh bị hỏng, thường dễ dàng hơn để giữ đúng chương trình.

+1

Thực ra, đây là một ý tưởng khá hay - ngoại trừ nó là một thư viện cấp thấp đang được viết. Các thói quen khởi tạo thư viện tạo ra các tập tin và sau đó ngã ba. Đứa trẻ tiếp tục làm tất cả công việc thực sự. Cha mẹ chỉ đơn giản ngồi đó, chờ đứa trẻ chấm dứt, sau đó loại bỏ các tập tin. –

+1

Điều này là phức tạp để biện minh trong một tập hợp các mục đích chung; chương trình có thể có các yêu cầu riêng về cấu trúc quy trình. Nếu nó được cho phép - bạn có đủ quyền kiểm soát của khách hàng - thì nó sẽ khá hiệu quả. –

1

Tôi chỉ tham gia stackoverflow và thấy các bạn ở đây :)

Nếu bạn vấn đề là để quản lý file mq và giữ chúng từ chồng chất, bạn không thực sự cần phải đảm bảo xóa tập tin khi chấm dứt. Nếu bạn chỉ muốn tập tin vô ích từ chồng chất lên, hơn là giữ một tạp chí có thể là tất cả những gì bạn cần. Thêm một mục vào tập tin tạp chí sau khi mở một mq, một mục khác khi nó được đóng lại, và khi thư viện của bạn được khởi tạo, kiểm tra sự không thống nhất trong nhật ký và thực hiện bất kỳ hành động nào cần thiết để sửa sự mâu thuẫn. Nếu bạn lo lắng về sự cố khi mq_open/mq_close đang được gọi, bạn cũng có thể thêm mục nhật ký ngay trước khi các chức năng đó được gọi.

0

Bạn có thực sự có cần tên để hiển thị không?

Giả sử bạn chọn tùy chọn hủy liên kết tệp ngay lập tức. Sau đó:

  • ưu tiên bỏ liên kết (2): đây là khá tốt ngoại trừ việc tôi cần các tập tin vẫn có thể nhìn thấy trong hệ thống tập tin (nếu không hệ thống là khó khăn hơn để giám sát/khắc phục sự cố).

    Bạn vẫn có thể gỡ lỗi trên tệp đã xóa, vì tệp sẽ vẫn hiển thị trong /proc/$pid/fd/. Miễn là bạn biết các pids của các quá trình của bạn, liệt kê các tập tin mở của họ phải dễ dàng.

  • tên cần được hiển thị trong quá trình hoạt động bình thường vì chúng được chia sẻ giữa các chương trình.

    Bạn vẫn có thể chia sẻ tệp đã bị xóa giữa các quy trình bằng cách chuyển qua bộ mô tả tệp trên ổ cắm miền Unix. Xem Portable way to pass file descriptor between different processes để biết thêm thông tin.

0
  • Có thư mục lưu trữ sách tạm thời trong thư mục dấu chấm của bạn.
  • Khi tạo tệp tạm thời, trước tiên hãy tạo tệp lưu giữ sách vào thư mục lưu giữ sách chứa đường dẫn hoặc UUID tới tệp tạm thời của bạn.
  • Tạo tệp tạm thời đó.
  • Khi tệp tạm thời bị xóa, sau đó xóa tệp lưu giữ sách.
  • Khi chương trình bắt đầu, hãy quét thư mục lưu giữ sách cho bất kỳ tệp nào chứa đường dẫn đến tệp tạm thời và cố gắng xóa chúng nếu tìm thấy, chúng xóa tệp lưu giữ sách.
  • (Đăng ồn ào nếu bất cứ bước nào thất bại.)

tôi không thấy cách để làm điều đó bất cứ cách nào đơn giản hơn. Đây là bản mẫu của bất kỳ chương trình chất lượng sản xuất nào phải trải qua; +500 dòng dễ dàng.

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