C: многопроцессный режим добавления stdio - PullRequest
3 голосов
/ 22 января 2012

Я написал этот код на C:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void random_seed(){
    struct timeval tim;
    gettimeofday(&tim, NULL);
    double t1=tim.tv_sec+(tim.tv_usec/1000000.0);
    srand (t1);
}

void main(){
    FILE *f;
    int i;
    int size=100;
    char *buf=(char*)malloc(size);

    f = fopen("output.txt", "a");
    setvbuf (f, buf, _IOFBF, size);
    random_seed();

    for(i=0; i<200; i++){
          fprintf(f, "[ xx - %d - 012345678901234567890123456789 - %d]\n", rand()%10, getpid());
          fflush(f);
    }

    fclose(f);
    free(buf);
}

Этот код открывает в режиме добавления файл и присоединяет 200 раз строку. Я установил buf размером 100, который может содержать полную строку. Затем я создал несколько процессов, выполняющих этот код, используя скрипт bash:

#!/bin/bash

gcc source.c
rm output.txt

for i in `seq 1 100`;
do
    ./a.out &
done

Я ожидал, что в выводе строки никогда не будут перепутаны, так как я прочитал, что при открытии файла с флагом O_APPEND смещение файла будет установлено до конца файла перед каждой записью, и я использую полностью буферизованный поток, но я получил первую строку каждого процесса, смешанного как это:

[ xx - [ xx - 7 - 012345678901234567890123456789 - 22545]

и несколько строк позже

2 - 012345678901234567890123456789 - 22589]

Похоже, что запись прерывается из-за вызова функции rand.

Так ... почему появляются эти строки? Это единственный способ предотвратить использование блокировок файлов ... даже если я использую только режим добавления?

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 22 января 2012

Вам потребуется самостоятельно реализовать некоторую форму управления параллелизмом, POSIX не дает никаких гарантий в отношении одновременных записей из нескольких процессов.Вы получаете некоторые гарантии для каналов, но не для обычных файлов, записанных в разные процессы.

Цитирование POSIX write():

Этот том POSIX.1-2008 не определяет поведение одновременной записи в файл из нескольких процессов. Приложения должны использовать некоторую форму управления параллелизмом.

(В конце раздела Обоснование .)

1 голос
/ 22 января 2012

Вы открываете файл в режиме полной буферизации. Это означает, что каждая строка вывода сначала попадает в буфер, а при переполнении буфера она сбрасывается в файл независимо от того, содержит ли он неполные строки. Это приводит к тому, что чанки вывода из разных процессов, одновременно записывающих в один и тот же файл, чередуются.

Простым решением было бы открыть файл в режиме буферизации строки _IOLBF, чтобы буфер очищался на каждой полной строке. Просто убедитесь, что размер буфера по крайней мере так же велик, как ваша самая длинная строка, в противном случае он будет заканчиваться записью неполных строк. Обычно буфер очищается одним системным вызовом write(), поэтому строки из разных процессов не пересекаются друг с другом.

Нет никакой гарантии, что системный вызов write() является атомарным для разных файловых систем, но обычно он работает, как и ожидалось, поскольку write() обычно блокирует дескриптор файла в ядре с мьютексом перед продолжением.

...