【问题标题】:using flock, open and close file to implement many readers single writer lock使用flock,打开和关闭文件实现多读单写锁
【发布时间】:2015-11-02 20:20:38
【问题描述】:

我有一个项目,它包含多个可以读取或写入单个数据库的进程。我希望使用系统调用flock/open/close来实现由锁文件同步的单写/多读锁。

在锁定失败时,任何重新尝试再次获取锁定的操作都将由请求锁定的更高级别进行(与自旋锁定不同)。

不幸的是,在测试这个模型时,它在没有锁定之前的解锁场景中失败了。 也许你可以帮我找出我做错了什么:

// keep read and write file descriptors as global variables.
// assuming no more than 1 thread can access db on each process. 

int write_descriptor=0;
int read_descriptor=0;

int lock_write() {
    if((write_descriptor = open(LOCKFILE, O_RDWR|O_CREAT,0644))<0) {
        return LOCK_FAIL;
    }

    if(flock(write_descriptor, LOCK_EX)<0) {
        close(write_descriptor);
        write_descriptor = 0;
        return LOCK_FAIL;
    }
    return LOCK_SUCCESS;
}

int unlock_write() {
    if(!write_descriptor) {
        // sanity: try to unlock before lock.
        return LOCK_FAIL;
    }

    if(flock(write_descriptor,LOCK_UN)<0) {
        // doing nothing because even if unlock failed, we
        // will close the fd anyway to release all locks.
    }
    close(write_descriptor);
    write_descriptor = 0;
    return LOCK_SUCCESS;
}


int lock_read() {
    if((read_descriptor = open(LOCKFILE,O_RDONLY))<0) {
        return LOCK_FAIL;
    }

    if(flock(read_descriptor, LOCK_SH)<0) {
        close(read_descriptor);
        return LOCK_FAIL;
    }
    return LOCK_SUCCESS;
}

int unlock_read() {
    if(!read_descriptor) {
        // sanity : try to unlock before locking first.
        return LOCK_FAIL;
    }

    if(flock(read_descriptor, LOCK_UN)<0) {
        // doing nothing because even if unlock failed, we
        // will close the fd anyway to release all locks.
    }
    close(read_descriptor);
    read_descriptor = 0;
    return LOCK_SUCCESS;
}


int read_db() {
    if(lock_read() != LOCK_SUCCESS) {
        return DB_FAIL;
    }
    // read from db
    if(unlock_read() != LOCK_SUCCESS) {
        // close fd also unlock - so we can fail here (can i assume that ?)
    }
}

int write_db() {
    if(lock_write() != LOCK_SUCCESS) {
        return DB_FAIL;
    }
    //write to db.
    if(unlock_write() != LOCK_SUCCESS) {
        // close fd also unlock - so we can fail here (can i assume that ?)
    }
}

【问题讨论】:

  • 这个进程是多线程的吗?如果是这样,这将不起作用,因为文件锁属于进程,而不是线程。
  • @DavidSchwartz,嗨。正如我在问题中提到的,我假设每个进程只有一个处理锁的线程(这就是我可以使用全局变量的原因。
  • 您能否更准确地了解它究竟是如何失败的。 (另外,为什么这被标记为“多线程”?)
  • 代码到达'unlock_read'方法,read_descriptor等于0。这意味着'lock_read'没有正常工作,或者根本没有被调用......
  • 等等。为什么要使用不同的描述符进行读取和写入?为什么不使用单个变量?你说只有一个线程在访问数据库,对吧?您的代码中存在错误未显示,或者您对如何使用此代码的描述不正确。

标签: c multithreading locking flock


【解决方案1】:

lock_readlock_write 中将其添加为第一行:

assert ((read_descriptor == 0) && (write_descriptor == 0));

unlock_read 中添加:

assert (read_descriptor != 0);

unlock_write 中添加:

assert (write_descriptor != 0);

并更改代码如下:

if(flock(read_descriptor, LOCK_SH)<0) {
    close(read_descriptor);
    return LOCK_FAIL;
}

到:

if(flock(read_descriptor, LOCK_SH)<0) {
    close(read_descriptor);
    read_descriptor = 0;
    return LOCK_FAIL;
}

对写入代码执行相同操作,以便在关闭描述符时,将相应的全局设置为零。 (你真的应该使用 -1 来表示无效的文件描述符,因为零是合法的。)

进行调试构建并运行它。当assert 出差时,你就是罪魁祸首。

【讨论】:

  • 好的,操作系统在我设法重现问题后,它似乎源自引用 file_descriptor=0,作为我的代码中的无效值。因此,它在锁定文件后人为地无法解锁文件。现在我有一个可执行文件可以 100% 地重现问题(这意味着每次选择的文件描述符都是零),所以我想知道为文件描述符选择值的策略是什么?
  • 我还验证了前 3 个非负数(0 1 和 2 )是为标准输入、标准输出和标准错误保留的。出于某种原因,我的项目并非如此。知道为什么吗?
  • @Zohar 我必须查看整个项目的设计才能理解原因,但是您拥有的某些代码不尊重该保留。例如,它可能正在关闭文件描述符零而不重新打开新的标准输入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
相关资源
最近更新 更多