讀寫鎖

作用:

(實現文件的讀寫同步)當一個進程正在讀或修改文件的某個部分時,阻止其他進程修改同一文件區。

訪問操作:

寫入鎖——又叫排它鎖

讀取鎖——又叫共享鎖

多進程訪問
(同一個進程訪問只會覆蓋已有的鎖)

已存在鎖	讀取鎖	寫入鎖
無	OK	OK
讀取鎖	OK	NG
寫入鎖	NG	NG
同一個進程訪問只會覆蓋已有的鎖
在訪問之前嘗試加鎖可以知道文件是否正在被讀寫。

加鎖區域:

文件鎖————整個文件上鎖

記錄鎖————文件部分內容上鎖

建議性鎖:

別名——勸解鎖/勸告鎖(寫鎖)和協同鎖/協作鎖(讀鎖)。

每個使用上鎖文件的進程都要檢查是否有鎖存在,要尊重已有的鎖。

要靠程序員遵守和實現。(不檢查是否有鎖的情況下可以強行讀寫)

強制性鎖:

——當文件被上鎖來進行寫入操作時,在鎖定該文件的進程釋放該鎖之前,內核會阻止任何對該文件的讀或寫訪問(open,read,write),每次讀寫訪問都要檢查鎖是否存在。

本質:

——內核讀寫文件自動處理。(內核實現,系統開銷大,影響性能,兼容性差)

設置:

1.重新掛載mount系統分區———sudo  mount  -o  remount,mand/

mand———允許強制鎖定

nomand——進制強制鎖定

2.修改文件權限————————sudo  chmod  g+s,g-x  文件

在文件執行時把進程的組ID置爲該文件的文件屬性。

系統	      建議性鎖	強制性鎖
Linux2.4.22	支持	支持
Solaris 9	支持	支持
Mac OS X 10.3	支持	不支持
FreeBSD 5.2.1	支持	不支持

建議性鎖函數:

int fcntl(int filedes,int  cmd,...,);

鎖操作形式:

int  fcntl(int fd,int cmd,struct flock* lock);

fd——文件描述符

cmd——命令:

獲取:F_GETLK

設置:

F_SETLK———加解鎖

F_SETLKW——加解鎖阻塞

struct  flock{

l_type;

l_whence;

l_start;——相對l_whence位置的偏移量

l_len;——鎖定區域的長度

l_pid;——當前佔用鎖的PID(只能用F_GETLK命令獲取)

};

l_type:

F_RDLCK——讀鎖

F_WRLCK——寫鎖

F_UNLCK——解鎖

l_whence:

SEEK_SET——以文件開頭爲鎖定的起始位置

SEEK_CUR——以目前文件讀寫位置爲鎖定的起始位置

SEEK_END——以文件結尾爲鎖定的起始位置

返回值:

-1——失敗

0——SET相關命令成功

代碼:

讀鎖:

#include <stdio.h>
#include <fcntl.h>

int main(int argc, char* argv[]){
	if(2!=argc){
		printf("usage:%s <pathname>\n",argv[0]);
		return 1;
	}
	int fd = open(argv[1],O_RDONLY);
	if(-1 == fd){
		perror("open error");
		return 1;
	}
	struct flock lock;
	lock.l_type = F_RDLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 0; 
	if(-1 == fcntl(fd,F_SETLK,&lock)){
		perror("fcntl error");
		return 1;
	}
	pause();
	close(fd);
}

解鎖(只能在加鎖的進程中解鎖):

// 本程序不能解鎖,因爲只有加鎖進程才能執行解鎖操作
#include <stdio.h>
#include <fcntl.h>

int main(int argc, char* argv[]){
	if(2!=argc){
		printf("usage:%s <pathname>\n",argv[0]);
		return 1;
	}
	int fd = open(argv[1],O_WRONLY);
	if(-1 == fd){
		perror("open error");
		return 1;
	}
	struct flock lock;
	lock.l_type = F_UNLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 0; 
	if(-1 == fcntl(fd,F_SETLKW,&lock)){
		perror("fcntl error");
		return 1;
	}
	pause();
	close(fd);
}

寫鎖+解鎖:

#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int fd;

void handler(int sig){
	struct flock lock;
	lock.l_type = F_UNLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 0; 
	if(-1 == fcntl(fd,F_SETLKW,&lock)){
		perror("fcntl error");
		exit(1);
	}
}

int main(int argc, char* argv[]){
	signal(SIGUSR1,handler);//用kill -s USR1 進程PID來傳輸信號。
	int c,start = 0,len = 0;
	while((c = getopt(argc,argv,"s:l:"))!=-1){
		switch(c){
		case 's':
			start = atoi(optarg);
			break;
		case 'l':
			len = atoi(optarg);
			break;
		}
	}

	if(optind != argc -1){
		printf("usage:%s [-s <start>] [-l <len>] <pathname>\n",argv[0]);
		return 1;
	}
	fd = open(argv[optind],O_WRONLY);
	if(-1 == fd){
		perror("open error");
		return 1;
	}
	struct flock lock;
	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = start;
	lock.l_len = len; 
	if(-1 == fcntl(fd,F_SETLKW,&lock)){
		perror("fcntl error");
		return 1;
	}
	pause();
	for(;;);
	close(fd);
}

查看上鎖情況:

#include <stdio.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char* argv[]){
	if(2!=argc){
		printf("usage:%s <pathname>\n",argv[0]);
		return 1;
	}
	int fd = open(argv[1],O_RDWR);
	if(-1 == fd){
		perror("open error");
		return 1;
	}
	struct flock lock;
	bzero(&lock,sizeof(lock));
	if(-1 == fcntl(fd,F_GETLK,&lock)){
		perror("fcntl error");
		return 1;
	}
	printf("file:%s,lock type:%d,start:%d,len:%d,by %d\n",argv[1],lock.l_type,lock.l_start,lock.l_len,lock.l_pid);

}

結果:

讀寫阻塞(讀的時候寫等待):

解寫鎖:


發佈了93 篇原創文章 · 獲贊 44 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章