IT培训机构|91免费精品视频|专注编程培训|91免费精品|软件开发培训_91免费国产视频_华清远见教育


linux 文件鎖的實現及其應用

分享到:
           

    文件鎖

    1.fcntl()函數說明

    前面講述的5個基本函數實現了文件的打開、讀/寫等基本操作,本節將討論在文件已經共享的情況下如何操作,也就是當多個用戶共同使用、操作一個文件的情況。這時,Linux通常采用的方法是給文件上鎖,來避免共享的資源產生競爭的狀態。

    文件鎖包括建議性鎖和強制性鎖。建議性鎖要求每個上鎖文件的進程都要檢查是否有鎖存在,并且尊重已有的鎖。在一般情況下,內核和系統都不使用建議性鎖。強制性鎖是由內核執行的鎖,當一個文件被上鎖進行寫入操作時,內核將阻止其他任何文件對其進行讀寫操作。采用強制性鎖對性能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。

    在Linux中,實現文件上鎖的函數有lockf()和fcntl(),其中lockf()用于對文件施加建議性鎖,而fcntl()不僅可以施加建議性鎖,還可以施加強制性鎖。同時,fcntl()還能對文件的某一記錄上鎖,也就是記錄鎖。

    記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共享鎖,它能夠使多個進程都能在文件的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時刻只能有一個進程在文件的某個部分建立寫入鎖。當然,在文件的同一部分不能同時建立讀取鎖和寫入鎖。

    fcntl()函數具有很豐富的功能,它可以對已打開的文件描述符進行各種操作,不僅包括管理文件鎖,還包括獲得設置文件描述符和文件描述符標志、文件描述符的復制等很多功能。本節主要介紹fcntl()函數建立記錄鎖的方法,關于它的其他操作,感興趣的讀者可以參看fcntl手冊。

    2.fcntl()函數格式

    用于建立記錄鎖的fcntl()函數語法要點如表2.6所示。

表2.6 fcntl()函數語法要點

所需頭文件 #include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
函數原型 int fcntl(int fd, int cmd, struct flock *lock)
函數傳入值 fd:文件描述符
cmd F_DUPFD:復制文件描述符
F_GETFD:獲得fd的close-on-exec標志,若標志未設置,則文件經過exec()函數之后仍保持打開狀態
F_SETFD:設置close-on-exec標志,該標志由參數arg的FD_CLOEXEC位決定
F_GETFL:得到open設置的標志
F_SETFL:改變open設置的標志
F_GETLK:根據lock描述,決定是否上文件鎖
F_SETLK:設置lock描述的文件鎖
F_SETLKW:這是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。
在無法獲取鎖時,會進入睡眠狀態;如果可以獲取鎖或者捕捉到信號則會返回
lock:結構為flock,設置記錄鎖的具體狀態,后面會詳細說明
函數返回值 成功:0
1:出錯

    這里,lock的結構如下所示:

    struct flock
    {
        short l_type;
        off_t l_start;
        short l_whence;
        off_t l_len;
        pid_t l_pid;
    }

    lock結構中每個變量的取值含義如表2.7所示。

表2.7 lock結構變量取值

l_type F_RDLCK:讀取鎖(共享鎖)
F_WRLCK:寫入鎖(排斥鎖)
F_UNLCK:解鎖
l_start 加鎖區域在文件中的相對位移量(字節),與l_whence值一起決定加鎖區域的起始位置
l_whence:
相對位移量的起點(同lseek的whence)
SEEK_SET:當前位置為文件的開頭,新位置為偏移量的大小
SEEK_CUR:當前位置為文件指針的位置,新位置為當前位置加上偏移量
SEEK_END:當前位置為文件的結尾,新位置為文件的大小加上偏移量的大小
l_len 加鎖區域的長度

    為加鎖整個文件,通常的方法是將l_start設置為0,l_whence設置為SEEK_SET,l_len設置為0。

    3.fcntl()使用實例

    下面首先給出了使用fcntl()函數的文件記錄鎖功能的代碼實現。在該代碼中,首先給flock結構體的對應位賦予相應的值。

    接著調用兩次fcntl()函數。用F_GETLK命令判斷是否可以進行flock結構所描述的鎖操作:若可以進行,則flock結構的l_type會被設置為F_UNLCK,其他域不變;若不可進行,則l_pid被設置為擁有文件鎖的進程號,其他域不變。

    用F_SETLK和F_SETLKW命令設置flock結構所描述的鎖操作,后者是前者的阻塞版。

    當第一次調用fcntl()時,使用F_GETLK命令獲得當前文件被上鎖的情況,由此可以判斷能不能進行上鎖操作;當第二次調用fcntl()時,使用F_SETLKW命令對指定文件進行上鎖/解鎖操作。因為F_SETLKW命令是阻塞式操作,所以,當不能把上鎖/解鎖操作進行下去時,運行會被阻塞,直到能夠進行操作為止。

    文件記錄鎖的功能代碼具體如下所示:

    /* lock_set.c */
    int lock_set(int fd, int type)
    {
        struct flock old_lock, lock;
        lock.l_whence = SEEK_SET;
        lock.l_start = 0;
        lock.l_len = 0;
        lock.l_type = type;
        lock.l_pid = -1;

        /* 判斷文件是否可以上鎖 */
        fcntl(fd, F_GETLK, &lock);
        if (lock.l_type != F_UNLCK)
        {
            /* 判斷文件不能上鎖的原因 */
            if (lock.l_type == F_RDLCK) /* 該文件已有讀取鎖 */
            {
                printf("Read lock already set by %d\n", lock.l_pid);
            }
            else if (lock.l_type == F_WRLCK) /* 該文件已有寫入鎖 */
            {
                printf("Write lock already set by %d\n", lock.l_pid);
            }
        }

        /* l_type 可能已被F_GETLK修改過 */
        lock.l_type = type;
        /* 根據不同的type值進行阻塞式上鎖或解鎖 */
        if ((fcntl(fd, F_SETLKW, &lock)) < 0)
        {
            printf("Lock failed:type = %d\n", lock.l_type);
            return 1;
        }

        switch(lock.l_type)
        {
            case F_RDLCK:
            {
                printf("Read lock set by %d\n", getpid());
            }
            break;
            case F_WRLCK:
            {
                printf("Write lock set by %d\n", getpid());
            }
            break;
            case F_UNLCK:
            {
                printf("Release lock by %d\n", getpid());
                return 1;
            }
            break;
            default:
            break;
        }/* end of switch */
        return 0;
    }

    下面的實例是文件寫入鎖的測試用例,這里首先創建了一個hello文件,之后對其上寫入鎖,后釋放寫入鎖。代碼如下所示:

    /* write_lock.c */
    #include <unistd.h>
    #include <sys/file.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "lock_set.c"

    int main(void)
    {
        int fd;

        /* 首先打開文件 */
        fd = open("hello",O_RDWR | O_CREAT, 0644);
        if(fd < 0)
        {
            printf("Open file error\n");
            exit(1);
        }

        /* 給文件上寫入鎖 */
        lock_set(fd, F_WRLCK);
        getchar();
        /* 給文件解鎖 */
        lock_set(fd, F_UNLCK);
        getchar();
        close(fd);
        exit(0);
    }

    為了能夠使用多個終端,更好地顯示寫入鎖的作用,本實例主要在PC上測試,讀者可將其交叉編譯,下載到目標板上運行。下面是在PC上的運行結果。為了使程序有較大的靈活性,筆者采用文件上鎖后由用戶輸入任意鍵使程序繼續運行。建議讀者開啟兩個終端,并且在兩個終端上同時運行該程序,以達到多個進程操作一個文件的效果。在這里,筆者首先運行終端一,請讀者注意終端二中的第一句。

    終端一:

    $ ./write_lock
    write lock set by 4994
    release lock by 4994

    終端二:

    $ ./write_lock
    write lock already set by 4994
    write lock set by 4997
    release lock by 4997

    由此可見,寫入鎖為互斥鎖,同一時刻只能有一個寫入鎖存在。

    接下來的程序是文件讀取鎖的測試用例,原理與上面的程序一樣。

    /* fcntl_read.c */
    #include <unistd.h>
    #include <sys/file.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "lock_set.c"

    int main(void)
    {
        int fd;
        fd = open("hello",O_RDWR | O_CREAT, 0644);
        if(fd < 0)
        {
            printf("Open file error\n");
            exit(1);
        }

        /* 給文件上讀取鎖 */
        lock_set(fd, F_RDLCK);
        getchar();
        /* 給文件解鎖 */
        lock_set(fd, F_UNLCK);
        getchar();
        close(fd);
        exit(0);
    }

    同樣開啟兩個終端,并首先啟動終端一上的程序,其運行結果如下所示。

    終端一:

    $ ./read_lock
    read lock set by 5009
    release lock by 5009

    終端二:

    $ ./read_lock
    read lock set by 5010
    release lock by 5010

    讀者可以將此結果與寫入鎖的運行結果相比較,可以看出,讀取鎖為共享鎖,當進程5009已設置讀取鎖后,進程5010仍然可以設置讀取鎖。

    本文選自華清遠見嵌入式培訓教材《從實踐中學嵌入式Linux應用程序開發》

   熱點鏈接:

   1、底層文件I/O操作的系統調用
   2、Linux中的文件及文件描述符
   3、Linux文件系統之虛擬文件系統(VFS)
   4、嵌入式文件系統構建
   5、Linux系統調用及用戶編程接口(API)

更多新聞>> 

主站蜘蛛池模板: 清扫器-聚氨酯清扫器-合金清扫器-四连杆自动纠偏-机械纠偏-锥辊纠偏-衡水涌泉机械科技有限公司 | 千斤顶-超薄电动千斤顶-电动液压千斤顶-液压螺母扳手-泰州杰克液压机械制造有限公司 | 中国C919飞机橡胶接头供应商-上海淞江减震器集团有限公司官方网站 | 酸碱废气中和塔-酸雾废气吸收塔-酸雾废气处理塔|首页-广州市佰镀通风设备有限公司 | 深圳市泰美乐纸制品有限公司-纸杯厂,一次性纸杯,广告纸杯,奶茶纸杯,试饮纸杯定做 | 山东致合必拓环保科技股份有限公司 | 郑州编织袋厂_郑州塑料编织袋_河南塑料编织袋厂-河南宏旺塑料编织袋厂家 | 锂电池破碎生产线|大型电池粉碎机|锂电池分离设备|电池破碎打粉设备-河南鑫恒岩重工科技有限公司 | 消字号牙膏代加工|面膜代加工|凝胶贴牌|漱口水贴牌-南京三盾药业有限公司-消字号牙膏代加工|面膜代加工|凝胶贴牌|漱口水贴牌-南京三盾药业有限公司 | 偏光显微镜-金相抛光机|预磨机|磨抛机|镶嵌机|切割机-上海蔡康光学仪器厂 | 装修工程-钢结构工程-环氧地坪漆-东莞市远鸣装饰工程有限公司 | 手术示教系统-实训示教系统-数字化手术室-直播录播系统 - 深圳市视源视讯技术有限公司 | 河北瑞峰医疗-河北护理床-河北医用病床-河北养老院护理床-河北护理床厂家-河北病床厂家-河北瑞峰医疗 | 呕吐毒素快速检测仪-黄曲霉毒素测定仪-玉米赤霉烯酮快速检测卡-南京微测生物科技有限公司 | 呼吸家官网|肺功能检测仪生产厂家|国产肺功能仪知名品牌|肺功能检测仪|肺功能测试仪|婴幼儿肺功能仪|弥散残气肺功能仪|肺功能测试系统|广州红象医疗科技有限公司|便携式肺功能仪|大肺功能仪|呼吸康复一体机|儿童肺功能仪|肺活量计|医用简易肺功能仪|呼吸康复系统|肺功能仪|弥散肺功能仪(大肺)|便携式肺功能检测仪|肺康复|呼吸肌力测定肺功能仪|肺功能测定仪|呼吸神经肌肉刺激仪|便携式肺功能 | 石家庄LED显示屏|石家庄显示屏|河北显示屏升级改造|石家庄科航光电科技有限公司_石家庄科航光电科技有限公司 | 营口新北方制糖有限公司 | 中证金服投资控股(深圳)有限公司| 长沙变频器维修,变频器维修,ABB变频器维修,西门子变频器维修,施耐德变频器维修,伺服驱动器维修,工业机器人维修,20年专业工控电气维修,长沙文铖电气设备有限公司_长沙文铖电气设备有限公司 | 液晶拼接屏_三星46寸/55寸/LG液晶拼接屏_深圳拼接墙厂家_电视大屏幕液晶拼接_高清工业级液晶监视器 | 消泡剂_有机硅消泡剂_分散剂_流平剂_氟碳表面活性剂-上海梓意化工有限公司 | 商标注册查询_商标注册代理公司_专利申请_版权登记-源智知识产权 | 郑州月嫂|月嫂培训|月嫂服务|郑州布卢家政服务有限公司 | 上海垃圾房,简易成品环保垃圾房,小区室外垃圾房,上海翼亭智能垃圾房厂家 | 噪声治理_噪音治理公司「杭州创雅环境科技」| 中标通国际认证(深圳)有限公司-知识产权管理体系认证-湖北知识产权贯标 | 九江监控安装_九江安防监控_九江弱电工程公司-九江百信科技有限公司 | 桥梁伸缩缝_桥梁伸缩缝厂家_桥梁伸缩缝价格-衡水淞皓路桥养护工程有限公司 | 青岛大倾角输送带厂家_橡胶挡边输送带_波纹状挡边输送带_大倾角输送带型号-青岛朗森橡胶有限公司 | 山东净化车间_净化工程_净化公司-山东海蓝净化装饰工程有限公司 山东金起起重机械有限公司[官网]-金桥银路悬臂吊,金起龙门吊,山东金起起重行吊,单梁起重机 | 营销型网站建设-企业高端网站设计制作公司-16年建站品牌 | 郑州编织袋厂_郑州塑料编织袋_河南塑料编织袋厂-河南宏旺塑料编织袋厂家 | 耐腐蚀磁力泵,直立式耐酸碱泵,立式耐酸碱泵,自吸式耐酸碱泵-杰凯泵业【官网】 | 苏州氮气弹簧厂家_江浙沪氮气弹簧价格_江苏氮气弹簧规格_BelleFlex碟形弹簧_昆山三虑五金机械有限公司 | 阻抗分析仪 阻抗测试仪 介电常数测试仪 充电枪测试仪-苏州腾斯凯电子科技有限公司 | 气动隔膜调节阀,气动比例调节隔膜阀|川熙流体设备百科 | 西安宣传片拍摄,陕西艺景网络科技有限公司资料备份,西安影视公司,视频拍摄制作,抖音视频制作,纪录片拍摄西安短视频摄影团队,西安抖音视频拍摄 | 陶瓷透水砖-透水砖厂家-淄博天之润生态科技有限公司 | 盆底肌修复仪器-产后康复脉冲磁训练仪-南京佳澜健康管理有限公司 | 苏州不锈钢_江苏不锈钢_江苏不锈钢板_苏州模具钢_苏州合金钢_苏州特种合金_苏州不锈钢板_304不锈钢棒_苏州塞硒五金制品有限公司 苏州ERP定制|苏州CRM|苏州OA|苏州BPM|进销存管理系统-苏州中尚信息科技有限公司 | 健身器材_健身器材厂_健身器材厂家-徐州兰士健身器材有限公司 |