2015-11-02 37 views
0

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

这个过程是多线程的吗?如果是这样,这将不起作用,因为文件锁由进程拥有,而不是线程。 –

+0

@DavidSchwartz,嗨。正如我在问题中提到的,我假设每个进程只有一个线程处理锁(这就是为什么我可以使用全局变量。 – Zohar81

+0

你能更准确地知道它是如何失败的吗?(另外,为什么这个标签'multithreading'?) –

回答

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旅行时,你会有你的罪魁祸首。

+0

好吧,我设法重现问题后,它似乎来自于引用file_descriptor = 0,作为我的代码中的无效值,因此,它锁定后人为失败解锁文件。一个e xecutable在100%的时间内重现问题(意味着每次选择的文件描述符都是零),所以我想知道为文件描述符选择值的策略是什么? – Zohar81

+0

我也验证过,前3个非负数(0 1和2)是为stdin stdout和stderr保留的。出于某种原因,我的项目并非如此。任何想法为什么? – Zohar81

+0

@Zohar我必须看到整个项目的设计才能理解为什么,但是您拥有的某些代码并不尊重该预订。例如,它可能会关闭文件描述符零并且不会重新打开新的标准输入。 –