Проблема синхронизации в Linux C при чтении и записи в файл одновременно - PullRequest
0 голосов
/ 12 июня 2018

Я пытаюсь протестировать возможные проблемы для одновременного чтения и записи в одни и те же файлы на встроенном устройстве с встроенным Linux.

У меня есть два процесса: Writer и Reader.Как следует из названий, Writer постоянно записывает 1 из 3 константных строк в 10 файлов один за другим, и в то же время Reader считывает одни и те же файлы и сравнивает выходные данные, чтобы убедиться в их правильности.Чтобы преодолеть проблемы с синхронизацией, я подумал, что мог бы использовать механизм обязательной блокировки файлов.

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

Я смонтировал tmpfs с включенной обязательной блокировкой файлов.

mount -t tmpfs -o mand,size=1m tmpfs /tmp2

Writer создает 10 файлов с обязательнойблокировка файлов включена.И в каждой итерации одна из трех приведенных ниже строк записывается в файлы.

const char* s1 = "31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
const char* s2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char* s3 = "************************************************************************";

Считыватель считывает эти файлы один за другим и сообщает о наличии несоответствия.И иногда (примерно один раз в каждые 1000 итераций, см. Коды ниже) читаются строки вроде:

"************************************************************************62862089986280348253421170679"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz********************"

Это именно та проблема, с которой я ожидал столкнуться.Меньшие строки пишутся поверх больших, а оставшиеся символы не удаляются.

Я пытался использовать fsync(fn) после записи в файл, но это не сработало.В любом случае это не нужно, так как это tmpfs.

В чем причина этого и что я могу сделать, чтобы избежать этого?

Вот коды для устройства записи и чтения

1026 * Писатель
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <errno.h>

const char* s1 = "31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
const char* s2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char* s3 = "************************************************************************";

int main()
{
    // create /tmp2/test directory
    if (mkdir("/tmp2/test", 0777) == -1) {
        if (errno != EEXIST) {
            perror("mkdir");
            return -1;
        }
    }

    // create 10 input files input0, input1, ..., input9
    for (int i = 0; i < 10; i++) {
        char path[50] = "/tmp2/test/input";
        sprintf(path + 16, "%d", i);
        FILE* fp = fopen(path, "w");
        if (fp == NULL) {
            fprintf(stderr, "Unable to create file %s\n", path);
            perror("create: ");
            return -1;
        }
        chmod(path, 02644); //mandatory file locking enabled
        fclose(fp);
    }

    // flock structure
    struct flock fl;
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    fl.l_pid = 0;

    // loop
    for(int step = 0; ; step++) {
        usleep(50000);

        for (int i = 0; i < 10; i++) {
            char path[50] = "/tmp2/test/input";
            sprintf(path + 16, "%d", i);

            FILE* fp = fopen(path, "w+");
            if (fp == NULL) {
                fprintf(stderr, "Unable to open file %s\n", path);
                perror("fopen: ");
                return -1;
            }
            int fd = fileno(fp);

            // place a write lock
            fl.l_type = F_WRLCK;
            if (fcntl(fd, F_SETLK, &fl) == -1) {
                perror("lock: ");
                return -1;
            }

            // write 1 of 3 strings
            if (step % 3 == 0) {
                write(fd, s1, strlen(s1));
            } else if (step % 3 == 1) {
                write(fd, s2, strlen(s2));
            } else {
                write(fd, s3, strlen(s3));
            }
            //fsync(fd);    // fsync should not be needed since this is a tmpfs

            // unlock
            fl.l_type = F_UNLCK;
            if (fcntl(fd, F_SETLK, &fl) == -1) {
                perror("lock: ");
                return -1;
            }

            fclose(fp);
        }
    }

    return 0;
}

Читатель:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>

const char* s1 = "31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
const char* s2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char* s3 = "************************************************************************";

int main()
{
    // counters for errors
    int err_ctr = 0;
    int read_err_ctr = 0;

    // loop
    for(int step = 0; ; step++) {
        usleep(50000);

        for (int i = 0; i < 10; i++) {
            char path[50] = "/tmp2/test/input";
            sprintf(path + 16, "%d", i);
            FILE* fp = fopen(path, "r");
            if (fp == NULL) {
                fprintf(stderr, "Unable to open file %s\n", path);
                perror("read: ");
                return -1;
            }

            // read the file
            char reading[150];
            if (fgets(reading, 150, fp) == NULL) {
                fclose(fp);
                read_err_ctr++;
                printf("Step = %d; ReadError = %d; from %s\n", step, read_err_ctr, path);
                continue;
            }
            fclose(fp);

            // continue if the string matches
            if (strcmp(reading, s1) == 0) {
                continue;
            } else if (strcmp(reading, s2) == 0) {
                continue;
            } else if (strcmp(reading, s3) == 0) {
                continue;
            }

            // print error
            err_ctr++;
            printf("Step = %d; Error = %d; I've read %s from %s\n", step, err_ctr, reading, path);
        }
    }

    return 0;
}
...