2015-11-02 57 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我必須看到整個項目的設計才能理解爲什麼,但是您擁有的某些代碼並不尊重該預訂。例如,它可能會關閉文件描述符零並且不會重新打開新的標準輸入。 –

相關問題