2012-03-26 35 views
8

Có thể sử dụng cùng lúc nhiều quy trình để truy cập (ghi) vào cùng một tệp không? Sử dụng đoạn mã sau, có vẻ như nó hoạt động, nhưng tôi có những nghi ngờ của tôi.Nhiều quy trình truy cập cùng một tệp

Trường hợp sử dụng trong cá thể là tệp thi hành được gọi mỗi khi nhận được email và ghi nhật ký của nó vào tệp trung tâm.

if (freopen(console_logfile, "a+", stdout) == NULL || freopen(error_logfile, "a+", stderr) == NULL) { 
    perror("freopen"); 
} 
printf("Hello World!"); 

này đang chạy trên CentOS và biên soạn như C.

+0

Có thể (tốt hơn) trùng lặp của [fopen hai quy trình] (http://stackoverflow.com/questions/1842909/fopen-two-processes). – blahdiblah

+0

Xem thêm [Có thể nhiều quá trình nối thêm vào một tệp bằng fopen mà không có bất kỳ vấn đề tương tranh nào không?] (Http://stackoverflow.com/questions/7552451/can-multiple-processes-append-to-a-file-using-fopen- không-bất kỳ-concurrency-prob). – blahdiblah

+2

Tôi không biết ngữ cảnh sử dụng nhật ký của bạn, nhưng tôi khuyên bạn nên xem 'syslog'. Có lẽ nó phù hợp với bạn. Làm việc với nó thực sự đơn giản. http://www.gnu.org/software/libc/manual/html_node/Submitting-Syslog-Messages.html –

Trả lời

8

Sử dụng các thiết bị IO tiêu chuẩn C giới thiệu một lớp mới của sự phức tạp; tập tin được sửa đổi chỉ qua write(2) -gia đình các cuộc gọi hệ thống (hoặc ánh xạ bộ nhớ, nhưng không được sử dụng trong trường hợp này) - trình bao bọc tiêu chuẩn IO có thể trì hoãn việc ghi vào tập tin một lúc và không thể gửi yêu cầu hoàn chỉnh trong một hệ thống gọi điện.

Các write(2) gọi riêng của mình nên cư xử tốt:

[...] If the file was 
    open(2)ed with O_APPEND, the file offset is first set to the 
    end of the file before writing. The adjustment of the file 
    offset and the write operation are performed as an atomic 
    step. 

    POSIX requires that a read(2) which can be proved to occur 
    after a write() has returned returns the new data. Note that 
    not all file systems are POSIX conforming. 

Do đó tiềm ẩn write(2) cuộc gọi của bạn sẽ cư xử đúng.

Đối với các luồng IO tiêu chuẩn C cao cấp hơn, bạn cũng cần phải chăm sóc bộ đệm. Chức năng setvbuf(3) có thể được sử dụng để yêu cầu đầu ra không được tạo ra, đầu ra có đầu ra theo đường đệm hoặc đầu ra được chặn theo khối. Thay đổi hành vi mặc định từ luồng này sang luồng khác - nếu đầu ra tiêu chuẩn và lỗi chuẩn được ghi vào thiết bị đầu cuối, thì chúng sẽ được lưu trữ theo dòng và không bị chặn theo mặc định. Nếu không, chặn khối là mặc định.

Bạn có thể muốn chọn theo cách thủ công dòng đệm nếu dữ liệu của bạn được định hướng theo dòng tự nhiên, để ngăn chặn dữ liệu xen kẽ.Nếu dữ liệu của bạn là không phải theo định hướng dòng, bạn có thể muốn sử dụng không được đệm hoặc để khối đệm nhưng tự xóa dữ liệu bất cứ khi nào bạn tích lũy một "đơn vị" đầu ra.

Nếu bạn đang viết nhiều hơn BUFSIZ byte tại một thời điểm, ghi của bạn có thể bị xen kẽ. Chức năng setvbuf(3) có thể giúp ngăn chặn sự xen kẽ.

Có thể còn quá sớm để nói về hiệu suất, nhưng việc xếp theo bộ đệm sẽ chậm hơn là chặn khối. Nếu bạn đang đăng nhập gần với tốc độ của đĩa, bạn có thể muốn thực hiện một cách tiếp cận hoàn toàn khác để đảm bảo việc viết của bạn không bị xen kẽ.

+0

Mẹo hay về 'setvbuf()' và các biến thể 'setbuf()', 'setbuffer()', và 'setlinebuf()'. Họ chỉ là những gì tôi cần. Cảm ơn, @sarnold. –

+0

Cảm ơn bạn đã chỉ ra rằng O_APPEND là cần thiết để đảm bảo điều chỉnh nguyên tử bù đắp tệp. Tôi bỏ qua nó từ quá trình đầu tiên mở tập tin, bởi vì nó cũng tạo ra nó (vì vậy 'append' dường như không thích hợp ..) – RobM

1

Câu trả lời này là không chính xác. Nó làm việc:

Vì vậy, tình trạng chủng tộc sẽ là:

  1. quá trình 1 mở nó cho append, sau đó
  2. sau quá trình 2 mở nó cho append, sau đó
  3. sau vẫn 1 viết và đóng, sau đó
  4. cuối cùng là 2 lần soạn và đóng.

Tôi rất ấn tượng nếu điều đó 'hiệu quả' vì điều này không rõ ràng đối với tôi về ý nghĩa của việc làm việc . Tôi giả sử 'làm việc' có nghĩa là tất cả các byte được viết bởi hai tiến trình là inthe log file? Tôi hy vọng rằng cả hai ký tự ghi bắt đầu từ cùng một byte bù trừ, vì vậy, một giá trị sẽ thay thế các byte khác byte. Tất cả sẽ được chấp nhận tối đa và bao gồm bước 3. và chỉ hiển thị như một vấn đề ở bước 4, Dường như một bài kiểm tra dễ dàng để viết: mở getchar ... viết gần.

Điều quan trọng là chúng có thể mở tệp đồng thời không? A giải pháp rõ ràng hơn nếu viết nhanh, là mở độc quyền.

Đối với một kiểm tra nhanh chóng trên hệ thống của bạn, hãy thử:

/* write the first command line argument to a file called foo 
* stackoverflow topic 9880935 
*/ 

#include <stdio.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 

int main (int argc, const char * argv[]) { 
    if (argc <2) { 
     fprintf(stderr, "Error: need some text to write to the file Foo\n"); 
     exit(1); 
    } 

    FILE* fp = freopen("foo", "a+", stdout); 

    if (fp == NULL) { 
     perror("Error failed to open file\n"); 
     exit(1); 
    } 

    fprintf(stderr, "Press a key to continue\n"); 
    (void) getchar();  /* Yes, I really mean to ignore the character */ 

    if (printf("%s\n", argv[1]) < 0) { 
     perror("Error failed to write to file: "); 
     exit(1);   
    } 

    fclose(fp); 

    return 0; 
} 
+0

Chúng không ghi đè lên nhau, từ 'man freopen':' a + ... Tiếp theo ghi vào tệp sẽ luôn luôn kết thúc ở phần cuối của tập tin hiện tại'. – blahdiblah

+0

@blahdiblah - có thể tôi đang thiếu thứ gì đó, nhưng làm thế nào họ có thể ** không ** ghi đè trong ví dụ của tôi? Cả hai quy trình đều mở để chắp thêm nhưng không ghi bất kỳ byte nào ở giai đoạn đó và do đó tệp có cùng độ dài cho cả hai mở. Sau đó cả hai đều viết. Không phải là tập tin bù đắp một thuộc tính của fd, và không phải là tập tin? – gbulmer

+0

Tôi chỉ báo cáo thông tin trong trang người đàn ông và kết quả thử nghiệm của riêng tôi. Tôi không thể nói chi tiết triển khai cơ bản. – blahdiblah

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