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


     1 #include <unistd.h>
     2 #include <stdlib.h>
     3 #include <stdio.h>
     4 #include <fcntl.h>
     5 
     6 const char *test_file = "/tmp/test_lock";//创建一个字符串常量指针指向临时文件
     7 
     8 int main() 
     9 {
    10     int file_desc;
    11     int byte_count;
    12     char *byte_to_write = "A";
    13     struct flock region_1;
    14     struct flock region_2;
    15     int res;
    16 
    17         /* open a file descriptor */
    18     file_desc = open(test_file, O_RDWR | O_CREAT, 0666);//指定的权限打开一个文件获得一个文件描述符
    19     if (!file_desc) 
    20     {
    21         fprintf(stderr, "Unable to open %s for read/write
    ", test_file);//失败打印这句话
    22         exit(EXIT_FAILURE);
    23     }
    24 
    25         /* put some data in the file */
    26     for(byte_count = 0; byte_count < 100; byte_count++) 
    27     {//循环
    28         (void)write(file_desc, byte_to_write, 1);//给文件描述符写一个字节的A
    29     }
    30 
    31         /* setup region 1, a shared lock, from bytes 10 -> 30 */
    32     region_1.l_type = F_RDLCK;//共享锁
    33     region_1.l_whence = SEEK_SET;//文件头开始
    34     region_1.l_start = 10;//第一个字节
    35     region_1.l_len = 20; //这个区域的字节数
    36     
    37         /* setup region 2, an exclusive lock, from bytes 40 -> 50 */
    38     region_2.l_type = F_WRLCK;//独占锁
    39     region_2.l_whence = SEEK_SET;//文件头开始
    40     region_2.l_start = 40;//第一个字节是40
    41     region_2.l_len = 10;//这个区域的长度是10
    42 
    43         /* now lock the file */
    44     printf("Process %d locking file
    ", getpid());
    45     res = fcntl(file_desc, F_SETLK, &region_1);//对文件描述符,设置文件锁,在指向flock结构的指针region_1处
    46     if (res == -1) fprintf(stderr, "Failed to lock region 1
    ");//失败返回-1
    47     res = fcntl(file_desc, F_SETLK, &region_2);//对文件描述符,设置文件锁,在指向flock结构的指针region_2处
    48     if (res == -1) fprintf(stderr, "Failed to lock region 2
    ");    //失败返回-1
    49 
    50         /* and wait for a while */
    51     sleep(60);//等待一分钟
    52 
    53     printf("Process %d closing file
    ", getpid());    
    54     close(file_desc);
    55     exit(EXIT_SUCCESS);
    56 }
    57 
    58 
    59 /*
    60 00----------
    61     
    62 10----------<----
    63          
    64                F_RDCLK共享锁
    65               
    66 30----------<----
    67 
    68 40----------<----
    69             F_WTCLK独占锁
    70 50----------<----
    71 
    72 
    73 
    74 
    75 
    76 
    77 
    78 
    79 90----------
    80 
    81 
    82 100---------
    83 
    84 */

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

     1 #include <unistd.h>
     2 #include <stdlib.h>
     3 #include <stdio.h>
     4 #include <fcntl.h>
     5 
     6 
     7 const char *test_file = "/tmp/test_lock";//创建一个字符串常量指针指向临时文件
     8 #define SIZE_TO_TRY 5        //宏定义一个常量
     9 
    10 void show_lock_info(struct flock *to_show);//定义函数的格式
    11 
    12 
    13 int main() {            //主函数
    14     int file_desc;
    15     int res;
    16     struct flock region_to_test;//定义flock结构
    17     int start_byte;
    18     
    19         /* open a file descriptor */
    20     file_desc = open(test_file, O_RDWR | O_CREAT, 0666);//按照指定的格式打开一个文件描述符给file_desc
    21     if (!file_desc) {
    22         fprintf(stderr, "Unable to open %s for read/write", test_file);
    23         exit(EXIT_FAILURE);
    24     }
    25 
    26     for (start_byte = 0; start_byte < 99; start_byte += SIZE_TO_TRY)
    27      {//设定循环格式
    28             /* set up the region we wish to test *///设定测试区域
    29         region_to_test.l_type = F_WRLCK;//独占锁
    30         region_to_test.l_whence = SEEK_SET;//区域:从文件头
    31         region_to_test.l_start = start_byte;//第一个字节:start_byte
    32         region_to_test.l_len = SIZE_TO_TRY;//区域的字节数
    33         region_to_test.l_pid = -1;     //记录带锁进程
    34 
    35         printf("Testing F_WRLCK on region from %d to %d
    ", //首先打印一句话
    36                start_byte, start_byte + SIZE_TO_TRY);//测试的区域,0-5,5-10,...,95-100
    37         
    38             /* now test the lock on the file */
    39         res = fcntl(file_desc, F_GETLK, &region_to_test);//获得指定描述符的文件的锁信息,
    40         if (res == -1) {
    41             fprintf(stderr, "F_GETLK failed
    ");
    42             exit(EXIT_FAILURE);
    43         }//文件打开成功的话继续执行
    44         if (region_to_test.l_pid != -1) {//设定测试区域失败,也就是如果测试区域的记录带锁进程不是-1
    45             printf("Lock would fail. F_GETLK returned:
    ");
    46             show_lock_info(&region_to_test);//打印出获得的区域的锁描述
    47         }
    48         else {
    49             printf("F_WRLCK - Lock would succeed
    ");//成功的话就是设定独占锁成功
    50         }
    51 
    52             /* now repeat the test with a shared (read) lock */
    53         
    54             /* set up the region we wish to test */
    55         region_to_test.l_type = F_RDLCK;//设定测试区域为共享锁
    56         region_to_test.l_whence = SEEK_SET;//区域的开始从文件头
    57         region_to_test.l_start = start_byte;//第一个字节:start_byte
    58         region_to_test.l_len = SIZE_TO_TRY;//区域的字节数
    59         region_to_test.l_pid = -1;     
    60 
    61         printf("Testing F_RDLCK on region from %d to %d
    ", 
    62                start_byte, start_byte + SIZE_TO_TRY);
    63         
    64             /* now test the lock on the file */
    65         res = fcntl(file_desc, F_GETLK, &region_to_test);
    66         if (res == -1) {
    67             fprintf(stderr, "F_GETLK failed
    ");
    68             exit(EXIT_FAILURE);
    69         }
    70         if (region_to_test.l_pid != -1) {
    71             printf("Lock would fail. F_GETLK returned:
    ");
    72             show_lock_info(&region_to_test);            
    73         }
    74         else {//获取文件锁状态和设置区域锁都成功的话,执行打印
    75             printf("F_RDLCK - Lock would succeed
    ");
    76         }
    77 
    78     } /* for *///大for循环结束
    79     
    80     close(file_desc);
    81     exit(EXIT_SUCCESS);
    82 }
    83 
    84 void show_lock_info(struct flock *to_show) {
    85     printf("	l_type %d, ", to_show->l_type);
    86     printf("l_whence %d, ", to_show->l_whence);
    87     printf("l_start %d, ", (int)to_show->l_start);        
    88     printf("l_len %d, ", (int)to_show->l_len);
    89     printf("l_pid %d
    ", to_show->l_pid);
    90 }

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

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

    下面是执行的结果

     1 jason@t61:~/c_program/544977-blp3e/chapter07$ ./lock3 &
     2 [1] 4903
     3 jason@t61:~/c_program/544977-blp3e/chapter07$ Process 4903 locking file
     4 ./lock4
     5 Testing F_WRLCK on region from 0 to 5
     6 F_WRLCK - Lock would succeed
     7 Testing F_RDLCK on region from 0 to 5
     8 F_RDLCK - Lock would succeed
     9 Testing F_WRLCK on region from 5 to 10
    10 F_WRLCK - Lock would succeed
    11 Testing F_RDLCK on region from 5 to 10
    12 F_RDLCK - Lock would succeed
    13 Testing F_WRLCK on region from 10 to 15
    14 Lock would fail. F_GETLK returned:
    15     l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
    16 Testing F_RDLCK on region from 10 to 15
    17 F_RDLCK - Lock would succeed
    18 Testing F_WRLCK on region from 15 to 20
    19 Lock would fail. F_GETLK returned:
    20     l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
    21 Testing F_RDLCK on region from 15 to 20
    22 F_RDLCK - Lock would succeed
    23 Testing F_WRLCK on region from 20 to 25
    24 Lock would fail. F_GETLK returned:
    25     l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
    26 Testing F_RDLCK on region from 20 to 25
    27 F_RDLCK - Lock would succeed
    28 Testing F_WRLCK on region from 25 to 30
    29 Lock would fail. F_GETLK returned:
    30     l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 4903
    31 Testing F_RDLCK on region from 25 to 30
    32 F_RDLCK - Lock would succeed
    33 Testing F_WRLCK on region from 30 to 35
    34 F_WRLCK - Lock would succeed
    35 Testing F_RDLCK on region from 30 to 35
    36 F_RDLCK - Lock would succeed
    37 Testing F_WRLCK on region from 35 to 40
    38 F_WRLCK - Lock would succeed
    39 Testing F_RDLCK on region from 35 to 40
    40 F_RDLCK - Lock would succeed
    41 Testing F_WRLCK on region from 40 to 45
    42 Lock would fail. F_GETLK returned:
    43     l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
    44 Testing F_RDLCK on region from 40 to 45
    45 Lock would fail. F_GETLK returned:
    46     l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
    47 Testing F_WRLCK on region from 45 to 50
    48 Lock would fail. F_GETLK returned:
    49     l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
    50 Testing F_RDLCK on region from 45 to 50
    51 Lock would fail. F_GETLK returned:
    52     l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 4903
    53 Testing F_WRLCK on region from 50 to 55
    54 F_WRLCK - Lock would succeed
    55 Testing F_RDLCK on region from 50 to 55
    56 F_RDLCK - Lock would succeed
    57 Testing F_WRLCK on region from 55 to 60
    58 F_WRLCK - Lock would succeed
    59 Testing F_RDLCK on region from 55 to 60
    60 F_RDLCK - Lock would succeed
    61 Testing F_WRLCK on region from 60 to 65
    62 F_WRLCK - Lock would succeed
    63 Testing F_RDLCK on region from 60 to 65
    64 F_RDLCK - Lock would succeed
    65 Testing F_WRLCK on region from 65 to 70
    66 F_WRLCK - Lock would succeed
    67 Testing F_RDLCK on region from 65 to 70
    68 F_RDLCK - Lock would succeed
    69 Testing F_WRLCK on region from 70 to 75
    70 F_WRLCK - Lock would succeed
    71 Testing F_RDLCK on region from 70 to 75
    72 F_RDLCK - Lock would succeed
    73 Testing F_WRLCK on region from 75 to 80
    74 F_WRLCK - Lock would succeed
    75 Testing F_RDLCK on region from 75 to 80
    76 F_RDLCK - Lock would succeed
    77 Testing F_WRLCK on region from 80 to 85
    78 F_WRLCK - Lock would succeed
    79 Testing F_RDLCK on region from 80 to 85
    80 F_RDLCK - Lock would succeed
    81 Testing F_WRLCK on region from 85 to 90
    82 F_WRLCK - Lock would succeed
    83 Testing F_RDLCK on region from 85 to 90
    84 F_RDLCK - Lock would succeed
    85 Testing F_WRLCK on region from 90 to 95
    86 F_WRLCK - Lock would succeed
    87 Testing F_RDLCK on region from 90 to 95
    88 F_RDLCK - Lock would succeed
    89 Testing F_WRLCK on region from 95 to 100
    90 F_WRLCK - Lock would succeed
    91 Testing F_RDLCK on region from 95 to 100
    92 F_RDLCK - Lock would succeed

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

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

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

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

      1 #include <unistd.h>
      2 #include <stdlib.h>
      3 #include <stdio.h>
      4 #include <fcntl.h>
      5 
      6 
      7 const char *test_file = "/tmp/test_lock";
      8 
      9 int main() 
     10 {
     11     int file_desc;
     12     struct flock region_to_lock;
     13     int res;
     14 
     15         /* open a file descriptor */
     16     file_desc = open(test_file, O_RDWR | O_CREAT, 0666);//打开文件描述符
     17     if (!file_desc) 
     18     {
     19         fprintf(stderr, "Unable to open %s for read/write
    ", test_file);
     20         exit(EXIT_FAILURE);
     21     }
     22 
     23     region_to_lock.l_type = F_RDLCK;//设定要锁定的区域及其格式
     24     region_to_lock.l_whence = SEEK_SET;//就是10-15字节处为读(共享)锁
     25     region_to_lock.l_start = 10;
     26     region_to_lock.l_len = 5;
     27     printf("Process %d, trying F_RDLCK, region %d to %d
    ", getpid(),
     28            (int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
     29     res = fcntl(file_desc, F_SETLK, &region_to_lock);//区设置锁
     30     if (res == -1) {
     31         printf("Process %d - failed to lock region
    ", getpid());//失败处理
     32     } else {
     33         printf("Process %d - obtained lock region
    ", getpid());//成功处理
     34     }
     35    
     36     region_to_lock.l_type = F_UNLCK;//设定一个区域区解锁
     37     region_to_lock.l_whence = SEEK_SET;//还是10-15字节处
     38     region_to_lock.l_start = 10;
     39     region_to_lock.l_len = 5;
     40     printf("Process %d, trying F_UNLCK, region %d to %d
    ", getpid(),
     41            (int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
     42     res = fcntl(file_desc, F_SETLK, &region_to_lock);
     43     if (res == -1) {
     44         printf("Process %d - failed to unlock region
    ", getpid());//失败处理
     45     } else {
     46         printf("Process %d - unlocked region
    ", getpid());//成功处理
     47     }
     48 
     49     region_to_lock.l_type = F_UNLCK;
     50     region_to_lock.l_whence = SEEK_SET;
     51     region_to_lock.l_start = 0;
     52     region_to_lock.l_len = 50;
     53     printf("Process %d, trying F_UNLCK, region %d to %d
    ", getpid(),
     54            (int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
     55     res = fcntl(file_desc, F_SETLK, &region_to_lock);//0-50设置解锁
     56     if (res == -1) {
     57         printf("Process %d - failed to unlock region
    ", getpid());
     58     } else {
     59         printf("Process %d - unlocked region
    ", getpid());
     60     }
     61     
     62     region_to_lock.l_type = F_WRLCK;
     63     region_to_lock.l_whence = SEEK_SET;
     64     region_to_lock.l_start = 16;
     65     region_to_lock.l_len = 5;
     66     printf("Process %d, trying F_WRLCK, region %d to %d
    ", getpid(),
     67            (int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
     68     res = fcntl(file_desc, F_SETLK, &region_to_lock);//16-21字节设置写锁
     69     if (res == -1) {
     70         printf("Process %d - failed to lock region
    ", getpid());
     71     } else {
     72         printf("Process %d - obtained lock on region
    ", getpid());
     73     }
     74 
     75     region_to_lock.l_type = F_RDLCK;
     76     region_to_lock.l_whence = SEEK_SET;
     77     region_to_lock.l_start = 40;
     78     region_to_lock.l_len = 10;
     79     printf("Process %d, trying F_RDLCK, region %d to %d
    ", getpid(),
     80            (int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
     81     res = fcntl(file_desc, F_SETLK, &region_to_lock);//40-50设置读锁
     82     if (res == -1) {
     83         printf("Process %d - failed to lock region
    ", getpid());
     84     } else {
     85         printf("Process %d - obtained lock on region
    ", getpid());
     86     }
     87     
     88     region_to_lock.l_type = F_WRLCK;
     89     region_to_lock.l_whence = SEEK_SET;
     90     region_to_lock.l_start = 16;
     91     region_to_lock.l_len = 5;
     92     printf("Process %d, trying F_WRLCK with wait, region %d to %d
    ", getpid(),
     93            (int)region_to_lock.l_start, (int)(region_to_lock.l_start + region_to_lock.l_len));
     94     res = fcntl(file_desc, F_SETLKW, &region_to_lock);//16-21设置写锁无法设置的时候的等待直到可以为止
     95     if (res == -1) {
     96         printf("Process %d - failed to lock region
    ", getpid());
     97     } else {
     98         printf("Process %d - obtained lock on region
    ", getpid());
     99     }
    100 
    101     printf("Process %d ending
    ", getpid());    
    102     close(file_desc);
    103     exit(EXIT_SUCCESS);
    104 }

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

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

    参考文献:

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

    //2015年06月28日 星期日 10时47分18秒


    万事走心 精益求美


  • 相关阅读:
    225. 用队列实现栈
    232. 用栈实现队列
    459.重复的子字符串(简单)
    28. 实现 strStr()(简单)
    剑指 Offer 58
    541. 反转字符串 II(简单)
    浏览器渲染页面的过程、重绘、重排以及页面优化
    隐藏一个元素的几种方法
    当我们在浏览器中输入一个URL后,发生了什么?
    Object.create() 和 new Object()、{} 的区别
  • 原文地址:https://www.cnblogs.com/kongchung/p/4605169.html
Copyright © 2020-2023  润新知