1. 程式人生 > 其它 >Linux 多程序鎖的幾種實現方案

Linux 多程序鎖的幾種實現方案

我們知道,多執行緒可以用多執行緒互斥量pthread_mutex_t實現執行緒之間上鎖,那麼多程序之間如何共享鎖呢?

1. 檔案鎖實現多程序鎖

由於檔案鎖是存放到位於記憶體的系統檔案表中, 所有程序/執行緒可通過系統訪問。如果不同程序使用同一檔案鎖(寫鎖/排他鎖),當取得檔案鎖時,程序可繼續執行;如果沒有取得鎖,則阻塞等待。而唯一標識該檔案的是檔案路徑,因此,可以通過一個共同的檔案路徑,來實現多程序鎖機制。
參見檔案鎖的本質核心和原理 | CSDN

關鍵點:
1)建立/開啟一個唯一路徑的檔案;
2)P操作,取得檔案的寫鎖(排他鎖);V操作,釋放檔案的鎖;

static struct flock lock_it; /* 用於加鎖的flock物件 */
static struct unlock_it;     /* 用於解鎖的flock物件 */
static int lock_fd = -1; 

void
my_lock_init(char *pathname)
{
    char lock_file[1024]; /* 存放檔名的臨時快取 */
    
    /* 由於mkstemp會修改引數的最後6個字元,為避免pathname是字串常量,需要將字串從pathname copy到臨時快取lock_file中,然後作為建立唯一臨時檔案的引數 */
    strncpy(lock_file, pathname, sizeof(lock_file));
    lock_fd = mkstemp(lock_file); /* 建立唯一的臨時檔案並開啟 */
    
    unlink(lock_file); /* 刪除指定檔名的檔案,如果有程序打開了該檔案,會在程序結束後所有指向該檔案的描述符都關閉後刪除檔案。這樣可以確保即使程式崩潰,臨時檔案也會完全消失 */

    /* 設定flock物件的寫鎖屬性 */
    lock_it.l_type = F_WRLCK;
    lock_it.l_whence = SEEK_SET;
    lock_it.l_start = 0;
    lock_it.l_len = 0;

    /* 設定flock物件的解鎖屬性 */
    unlock_it.l_type = F_UNLCK;
    unlock_it.l_whence = SEEK_SET;
    unlock_it.l_start = 0;
    unlock_it.l_len = 0;
}

void
my_lock_wait()
{
    int rc;
    
    /* 取得寫鎖,如果阻塞等待時被中斷喚醒,則繼續恢復阻塞等待鎖資源 */
    whilel ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) {
        if (errno == EINTR) continue;
        else err_sys("my_lock_wait fcntl error");  /* 如果沒有呼叫my_lock_init就直接呼叫fcntl,將會失敗 */
    }
}

void 
my_lock_release()
{
    if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0)
        err_sys("my_lock_release fcntl error");
}

2. 多執行緒鎖實現多程序鎖

多執行緒之間天然共享記憶體/變數,而多程序各有自己的程序空間,它們之間是不共享資料的

2個關鍵步驟
1)互斥鎖變數存放到共享記憶體;
2)設定互斥鎖變數的程序共享屬性(PTHREAD_PROCESS_SHARED);

static pthread_mutex_t *mptr; /* 互斥鎖變數指標,互斥鎖變數存放到共享記憶體 */

/**
* 多程序互斥鎖變數初始化
*/
void
my_lock_init()
{
    int fd;
    pthread_mutexattr_t mattr;

    /* 新建共享記憶體區域,但不對映到實際的普通檔案 */
    fd = open("/dev/zero", O_RDWR, 0);
    if (fd < 0) err_sys("open error");
    mptr = mmap(0, sizeof(pthread_mutex_t), PORT_READ | PORT_WRITE, MAP_SHARED, fd, 0);
    if (mptr == MAP_FAILED) err_sys("mmap");
    if (close(fd)) err_sys("close error");
    
    pthread_mutexattr_init(&mattr);
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    phtread_mutex_init(mptr, &mattr);
}

/**
* 加鎖
*/
void
my_lock_wait()
{
  pthread_mutex_lock(mptr);
}

/**
* 解鎖
*/
void 
my_lock_release()
{
    pthread_mutex_unlock(mptr);
}