Linux C中的同步问题同时读取和写入文件

时间:2018-06-12 12:37:25

标签: c linux file synchronization locking

我正在尝试测试在嵌入了Linux的嵌入式设备上同时读取和写入相同文件的可能问题。

我有两个过程:Writer和Reader。顾名思义,Writer不断地将3个const字符串中的1个逐个写入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 = "************************************************************************";

Reader逐个读取这些文件并报告是否存在不匹配。它偶尔(大约每1000次迭代中一次,见下面的代码)读取如下字符串:

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

这正是我期待遇到的问题。较小的字符串写在较大的字符串之上,其余字符不会被删除。

我在写入文件后尝试使用fsync(fn),但它没有用。无论如何都不需要它,因为这是一个tmpfs。

这是什么原因,我该怎么做才能避免这种情况?

以下是Writer和Reader的代码:

作家

#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;
}

0 个答案:

没有答案