您的位置:首页 > 其它

fcntl实现【文件区锁定】,【区锁定测试】,【区域锁定竞争】程序

2015-06-28 10:22 591 查看
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

const char *test_file = "/tmp/test_lock";//创建一个字符串常量指针指向临时文件

int main()
{
int file_desc;
int byte_count;
char *byte_to_write = "A";
struct flock region_1;
struct flock region_2;
int res;

/* open a file descriptor */
file_desc = open(test_file, O_RDWR | O_CREAT, 0666);//指定的权限打开一个文件获得一个文件描述符
if (!file_desc)
{
fprintf(stderr, "Unable to open %s for read/write\n", test_file);//失败打印这句话
exit(EXIT_FAILURE);
}

/* put some data in the file */
for(byte_count = 0; byte_count < 100; byte_count++)
{//循环
(void)write(file_desc, byte_to_write, 1);//给文件描述符写一个字节的A
}

/* setup region 1, a shared lock, from bytes 10 -> 30 */
region_1.l_type = F_RDLCK;//共享锁
region_1.l_whence = SEEK_SET;//文件头开始
region_1.l_start = 10;//第一个字节
region_1.l_len = 20; //这个区域的字节数

/* setup region 2, an exclusive lock, from bytes 40 -> 50 */
region_2.l_type = F_WRLCK;//独占锁
region_2.l_whence = SEEK_SET;//文件头开始
region_2.l_start = 40;//第一个字节是40
region_2.l_len = 10;//这个区域的长度是10

/* now lock the file */
printf("Process %d locking file\n", getpid());
res = fcntl(file_desc, F_SETLK, ®ion_1);//对文件描述符,设置文件锁,在指向flock结构的指针region_1处
if (res == -1) fprintf(stderr, "Failed to lock region 1\n");//失败返回-1
res = fcntl(file_desc, F_SETLK, ®ion_2);//对文件描述符,设置文件锁,在指向flock结构的指针region_2处
if (res == -1) fprintf(stderr, "Failed to lock region 2\n");    //失败返回-1

/* and wait for a while */
sleep(60);//等待一分钟

printf("Process %d closing file\n", getpid());
close(file_desc);
exit(EXIT_SUCCESS);
}

/*
00----------

10----------<----

F_RDCLK共享锁

30----------<----

40----------<----
F_WTCLK独占锁
50----------<----

90----------

100---------

*/


上面的代码设置10-30字节上为读锁也就是共享锁,在40-50区域设置的是写锁也就是独占锁,下面是测试程序:

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

const char *test_file = "/tmp/test_lock";//创建一个字符串常量指针指向临时文件
#define SIZE_TO_TRY 5        //宏定义一个常量

void show_lock_info(struct flock *to_show);//定义函数的格式

int main() {            //主函数
int file_desc;
int res;
struct flock region_to_test;//定义flock结构
int start_byte;

/* open a file descriptor */
file_desc = open(test_file, O_RDWR | O_CREAT, 0666);//按照指定的格式打开一个文件描述符给file_desc
if (!file_desc) {
fprintf(stderr, "Unable to open %s for read/write", test_file);
exit(EXIT_FAILURE);
}

for (start_byte = 0; start_byte < 99; start_byte += SIZE_TO_TRY)
{//设定循环格式
/* set up the region we wish to test *///设定测试区域
region_to_test.l_type = F_WRLCK;//独占锁
region_to_test.l_whence = SEEK_SET;//区域:从文件头
region_to_test.l_start = start_byte;//第一个字节:start_byte
region_to_test.l_len = SIZE_TO_TRY;//区域的字节数
region_to_test.l_pid = -1;     //记录带锁进程

printf("Testing F_WRLCK on region from %d to %d\n", //首先打印一句话
start_byte, start_byte + SIZE_TO_TRY);//测试的区域,0-5,5-10,...,95-100

/* now test the lock on the file */
res = fcntl(file_desc, F_GETLK, ®ion_to_test);//获得指定描述符的文件的锁信息,
if (res == -1) {
fprintf(stderr, "F_GETLK failed\n");
exit(EXIT_FAILURE);
}//文件打开成功的话继续执行
if (region_to_test.l_pid != -1) {//设定测试区域失败,也就是如果测试区域的记录带锁进程不是-1
printf("Lock would fail. F_GETLK returned:\n");
show_lock_info(®ion_to_test);//打印出获得的区域的锁描述
}
else {
printf("F_WRLCK - Lock would succeed\n");//成功的话就是设定独占锁成功
}

/* now repeat the test with a shared (read) lock */

/* set up the region we wish to test */
region_to_test.l_type = F_RDLCK;//设定测试区域为共享锁
region_to_test.l_whence = SEEK_SET;//区域的开始从文件头
region_to_test.l_start = start_byte;//第一个字节:start_byte
region_to_test.l_len = SIZE_TO_TRY;//区域的字节数
region_to_test.l_pid = -1;

printf("Testing F_RDLCK on region from %d to %d\n",
start_byte, start_byte + SIZE_TO_TRY);

/* now test the lock on the file */
res = fcntl(file_desc, F_GETLK, ®ion_to_test);
if (res == -1) {
fprintf(stderr, "F_GETLK failed\n");
exit(EXIT_FAILURE);
}
if (region_to_test.l_pid != -1) {
printf("Lock would fail. F_GETLK returned:\n");
show_lock_info(®ion_to_test);
}
else {//获取文件锁状态和设置区域锁都成功的话,执行打印
printf("F_RDLCK - Lock would succeed\n");
}

} /* for *///大for循环结束

close(file_desc);
exit(EXIT_SUCCESS);
}

void show_lock_info(struct flock *to_show) {
printf("\tl_type %d, ", to_show->l_type);
printf("l_whence %d, ", to_show->l_whence);
printf("l_start %d, ", (int)to_show->l_start);
printf("l_len %d, ", (int)to_show->l_len);
printf("l_pid %d\n", to_show->l_pid);
}


上面的测试程序是按照5个字节为单位测试整个区域,打印出测试的结果。

【第一个点】上面的l_pid设置为-1是一个非法值,但是要是测试区域没被锁定,不会修改这个值,要是被锁定的话,这个值会被修改,打印处相应的信息。

下面是执行的结果

jason@t61:~/c_program/544977-blp3e/chapter07$ ./lock3 &
[1] 4903
jason@t61:~/c_program/544977-blp3e/chapter07$ Process 4903 locking file
./lock4
Testing F_WRLCK on region from 0 to 5
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 0 to 5
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 5 to 10
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 5 to 10
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 10 to 15
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
Testing F_RDLCK on region from 10 to 15
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 15 to 20
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
Testing F_RDLCK on region from 15 to 20
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 20 to 25
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
Testing F_RDLCK on region from 20 to 25
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 25 to 30
Lock would fail. F_GETLK returned:
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
Testing F_RDLCK on region from 25 to 30
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 30 to 35
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 30 to 35
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 35 to 40
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 35 to 40
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 40 to 45
Lock would fail. F_GETLK returned:
l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
Testing F_RDLCK on region from 40 to 45
Lock would fail. F_GETLK returned:
l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
Testing F_WRLCK on region from 45 to 50
Lock would fail. F_GETLK returned:
l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
Testing F_RDLCK on region from 45 to 50
Lock would fail. F_GETLK returned:
l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
Testing F_WRLCK on region from 50 to 55
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 50 to 55
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 55 to 60
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 55 to 60
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 60 to 65
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 60 to 65
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 65 to 70
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 65 to 70
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 70 to 75
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 70 to 75
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 75 to 80
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 75 to 80
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 80 to 85
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 80 to 85
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 85 to 90
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 85 to 90
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 90 to 95
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 90 to 95
F_RDLCK - Lock would succeed
Testing F_WRLCK on region from 95 to 100
F_WRLCK - Lock would succeed
Testing F_RDLCK on region from 95 to 100
F_RDLCK - Lock would succeed


可以看到,10-30字节,以前设定的是读锁,也就是共享锁,在这个区域的测试都是可以写共享锁,不能写独占锁,l_type值为0表示读锁存在。

     40-50字节,以前设定的是写锁,也就是独占锁,在这个区域的测试都是失败的,l_type的值为1表示写锁存在。

    其他的区域,也就是未被锁定的区域写任何锁都会成功。【这俩个测试是分别设置和分别执行的才可以不受相互之间的影响】

下面试图对锁定的区域进行锁的设置也就是竞争,看看发生什么事情

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

const char *test_file = "/tmp/test_lock";

int main()
{
int file_desc;
struct flock region_to_lock;
int res;

/* open a file descriptor */
file_desc = open(test_file, O_RDWR | O_CREAT, 0666);//打开文件描述符
if (!file_desc)
{
fprintf(stderr, "Unable to open %s for read/write\n", test_file);
exit(EXIT_FAILURE);
}

region_to_lock.l_type = F_RDLCK;//设定要锁定的区域及其格式
region_to_lock.l_whence = SEEK_SET;//就是10-15字节处为读(共享)锁
region_to_lock.l_start = 10;
region_to_lock.l_len = 5;
printf("Process %d, trying F_RDLCK, region %d to %d\n", getpid(),
(int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
res = fcntl(file_desc, F_SETLK, ®ion_to_lock);//区设置锁
if (res == -1) {
printf("Process %d - failed to lock region\n", getpid());//失败处理
} else {
printf("Process %d - obtained lock region\n", getpid());//成功处理
}

region_to_lock.l_type = F_UNLCK;//设定一个区域区解锁
region_to_lock.l_whence = SEEK_SET;//还是10-15字节处
region_to_lock.l_start = 10;
region_to_lock.l_len = 5;
printf("Process %d, trying F_UNLCK, region %d to %d\n", getpid(),
(int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
res = fcntl(file_desc, F_SETLK, ®ion_to_lock);
if (res == -1) {
printf("Process %d - failed to unlock region\n", getpid());//失败处理
} else {
printf("Process %d - unlocked region\n", getpid());//成功处理
}

region_to_lock.l_type = F_UNLCK;
region_to_lock.l_whence = SEEK_SET;
region_to_lock.l_start = 0;
region_to_lock.l_len = 50;
printf("Process %d, trying F_UNLCK, region %d to %d\n", getpid(),
(int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
res = fcntl(file_desc, F_SETLK, ®ion_to_lock);//0-50设置解锁
if (res == -1) {
printf("Process %d - failed to unlock region\n", getpid());
} else {
printf("Process %d - unlocked region\n", getpid());
}

region_to_lock.l_type = F_WRLCK;
region_to_lock.l_whence = SEEK_SET;
region_to_lock.l_start = 16;
region_to_lock.l_len = 5;
printf("Process %d, trying F_WRLCK, region %d to %d\n", getpid(),
(int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
res = fcntl(file_desc, F_SETLK, ®ion_to_lock);//16-21字节设置写锁
if (res == -1) {
printf("Process %d - failed to lock region\n", getpid());
} else {
printf("Process %d - obtained lock on region\n", getpid());
}

region_to_lock.l_type = F_RDLCK;
region_to_lock.l_whence = SEEK_SET;
region_to_lock.l_start = 40;
region_to_lock.l_len = 10;
printf("Process %d, trying F_RDLCK, region %d to %d\n", getpid(),
(int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
res = fcntl(file_desc, F_SETLK, ®ion_to_lock);//40-50设置读锁
if (res == -1) {
printf("Process %d - failed to lock region\n", getpid());
} else {
printf("Process %d - obtained lock on region\n", getpid());
}

region_to_lock.l_type = F_WRLCK;
region_to_lock.l_whence = SEEK_SET;
region_to_lock.l_start = 16;
region_to_lock.l_len = 5;
printf("Process %d, trying F_WRLCK with wait, region %d to %d\n", getpid(),
(int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
res = fcntl(file_desc, F_SETLKW, ®ion_to_lock);//16-21设置写锁无法设置的时候的等待直到可以为止
if (res == -1) {
printf("Process %d - failed to lock region\n", getpid());
} else {
printf("Process %d - obtained lock on region\n", getpid());
}

printf("Process %d ending\n", getpid());
close(file_desc);
exit(EXIT_SUCCESS);
}


下面是这个程序的执行结果和分析:

ason@t61:~/c_program/544977-blp3e/chapter07$ gcc lock5.c -o lock5
jason@t61:~/c_program/544977-blp3e/chapter07$ ./lock3 &
[1] 5091
jason@t61:~/c_program/544977-blp3e/chapter07$ Process 5091 locking file
./lock5
Process 5092, trying F_RDLCK, region 10 to 15//以前是读锁
Process 5092 - obtained lock region        //设置读锁成功
Process 5092, trying F_UNLCK, region 10 to 15//以前是读锁
Process 5092 - unlocked region            //解锁成功
Process 5092, trying F_UNLCK, region 0 to 50    //以前有读锁,有写锁,但是整个区域没有写锁定
Process 5092 - unlocked region            //不是解锁成功,因为本身没锁
Process 5092, trying F_WRLCK, region 16 to 21//以前是读锁
Process 5092 - failed to lock region        //试图设置写锁失败了
Process 5092, trying F_RDLCK, region 40 to 50//以前是写锁
Process 5092 - failed to lock region        //试图设置读锁失败了【就是我在写就算读也不行这是独占】
Process 5092, trying F_WRLCK with wait, region 16 to 21//以前是读锁就是共享锁,试图设置区域为独占锁
Process 5091 closing file            //这次是等待的方式进行的,等到读锁这片区域的Lock3程序
Process 5092 - obtained lock on region        //关闭文件释放锁之后,进行锁定。
Process 5092 ending
[1]+  已完成               ./lock3
jason@t61:~/c_program/544977-blp3e/chapter07$


参考文献:

Linux程序设计 Neil Matthew 第七章 数据管理

//2015年06月28日 星期日 10时47分18秒
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: