使用flock, open and close file实现多读单写锁

using flock, open and close file to implement many readers single writer lock

我有一个项目包含多个进程,可以读取或写入单个数据库。我希望使用系统调用 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 ?)
    }
}

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 绊倒时,罪魁祸首就是你。