2012-03-26 9 views
8

여러 프로세스가 동시에 같은 파일에 액세스 (쓰기)해도 괜찮습니까? 다음 코드를 사용하면 작동하는 것처럼 보이지만 의심이됩니다.동일한 파일에 액세스하는 여러 프로세스

인스턴스의 유스 케이스는 이메일을 수신 할 때마다 호출되어 실행 결과를 중앙 파일에 기록하는 실행 파일입니다.

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

은에 CentOS에서 실행 C.

+0

[두 개의 프로세스를 열 수 있습니다] 복제본이 가능합니다 (http://stackoverflow.com/questions/1842909/fopen-two-processes). – blahdiblah

+0

[여러 프로세스가 동시성 문제없이 fopen을 사용하여 파일에 추가 할 수 있습니까?] (http://stackoverflow.com/questions/7552451/can-multiple-processes-append-to-a-file-using-fopen- without-any-concurrency-prob). – blahdiblah

+2

로그 사용에 대한 컨텍스트를 알 수는 없지만'syslog'를 살펴 보는 것이 좋습니다. 어쩌면 그것은 당신에게 어울립니다. 그것으로 작업하는 것은 정말 간단합니다. http://www.gnu.org/software/libc/manual/html_node/Submitting-Syslog-Messages.html –

답변

8

을 C 표준 IO 기능을 사용하면 복잡한 새 레이어를 소개합니다; 파일은 write(2)-family of system calls (또는 메모리 매핑,하지만이 경우에는 사용되지 않음)를 통해 수정됩니다. C 표준 IO 래퍼는 한동안 파일에 쓰는 것을 연기 할 수 있으며 하나의 시스템에서 완전한 요청을 제출할 수 없습니다 요구.

write(2) 전화 자체는 잘 작동한다 :

[...] 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. 

은 따라서 귀하의 기본 write(2) 전화가 제대로 작동합니다.

상위 C 표준 IO 스트림의 경우 버퍼링도 처리해야합니다. setvbuf(3) 함수는 버퍼되지 않은 출력, 라인 버퍼 출력 또는 블록 버퍼 출력을 요청하는 데 사용할 수 있습니다. 기본 동작은 스트림에서 스트림으로 변경됩니다. 표준 출력 및 표준 오류가 터미널에 쓰고 있으면 기본적으로 라인 버퍼링되고 버퍼링되지 않습니다. 그렇지 않으면 블록 버퍼링이 기본값입니다.

인터리브 된 데이터를 방지하기 위해 데이터가 자연스럽게 줄 단위 인 경우 수동으로 줄 버퍼를 선택하는 것이 좋습니다.데이터가 이 아니고 라인 지향 인 인 경우 버퍼링을 사용하지 않거나 블록 버퍼를 그대로두고 출력의 단일 "단위"를 누적 할 때마다 수동으로 데이터를 플러시 할 수 있습니다.

한 번에 BUFSIZ 바이트를 초과하여 쓰는 경우 쓰기가 인터리브 될 수 있습니다. setvbuf(3) 함수는 인터리빙을 방지하는 데 도움이 될 수 있습니다.

성능에 대해서는 이야기하기에는 시기상조이지만, 라인 버퍼링은 블록 버퍼링보다 느려질 것입니다. 디스크 속도 가까이에서 로깅하는 경우 쓰기가 인터리브되지 않도록 완전히 다른 방법을 사용하는 것이 좋습니다.

+0

'setvbuf()'와 그 변종'setbuf()','setbuffer()','setlinebuf()'에 관한 유용한 팁. 그것들은 내가 필요한 것일 뿐이었다. 고마워, @ sarnold. –

+0

파일 오프셋의 원자 적 조정을 보장하려면 O_APPEND가 필요하다는 점을 지적 해 주셔서 감사합니다. 파일을 여는 첫 번째 프로세스에서 생략했습니다. (또한 'append'가 적절하지 않은 것처럼 보입니다.) – RobM

1

이 대답은 정확로 컴파일됩니다.

그래서 경쟁 조건은 다음과 같습니다 :

  1. 처리 한 후, APPEND 위해 열립니다
  2. 이후 과정이 나중에 여전히
  3. 1 명 기입 한 후, APPEND을 위해 그것을 열어이 작업을 수행 닫히면
  4. 마지막으로 2가 닫히고 닫힙니다.

작동하지 않으면 의미가 분명하지 않기 때문에 '작동'이라면 감동 할 것입니다. 나는 'working'이란 두 개의 프로세스에 의해 작성된 모든 바이트가 이라는 것을 의미한다고 가정한다. 나는 그들 모두가 같은 바이트 오프셋에서 시작하므로, 하나는 다른 바이트를 대체 할 것이라고 예상한다. 바이트. 그것은 모두 최대 괜찮을 것이며 3 단계를 포함하고 1235 단계에서 문제로만 을 표시합니다. 작성하기 쉬운 테스트처럼 보입니다. open getchar ... write close.

파일을 동시에 열어 볼 수 있습니까? A 쓰기가 빠르면 더 명확한 해결책은 독점적으로 열리는 것입니다.

시스템의 빠른 확인을 위해

, 시도 :

/* 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

그들은'man freopen'에서 서로 겹쳐 쓰지 않습니다 :'a + ... 그 다음 파일에 씁니다. 파일의 현재 시점에서 끝납니다 .' – blahdiblah

+0

@blahdiblah - 어쩌면 내가 뭔가를 놓치고 있지만, 어떻게 ** ** 내 예제에서 덮어 쓸 수 있습니까? 두 프로세스 모두 append를 위해 열리지 만 그 단계에서 바이트를 쓰지 않기 때문에 두 파일 모두 같은 길이가됩니다. 그런 다음 둘 다 씁니다. 파일이 파일이 아닌 fd의 속성으로 오프셋되어 있지 않습니까? – gbulmer

+0

맨 페이지의 정보와 내 테스트의 결과 만보고합니다. 기본 구현 세부 사항을 말할 수는 없습니다. – blahdiblah

관련 문제