Linux 系统编程的一种技巧:使用 fcntl() 实现读写锁

胖静君_2921

胖静君_2921

2024-02-13

1300人浏览

转载

读写锁是一种常用的同步机制,它可以让多个进程或者线程对同一个资源进行并发的读操作,或者互斥的写操作,从而提高系统的效率和安全性。在 linux 系统编程中,有多种方法可以实现读写锁,如使用 pthread 库、使用文件锁等。本文将为你介绍一种使用 fcntl() 系统调用实现读写锁的方法,以及它的原理、用法和优缺点,让你在 linux 系统编程中更好地使用和理解这种技巧。

Linux 系统编程的一种技巧:使用 fcntl() 实现读写锁

在多进程对同一个文件进行读写访问时,为了保证数据的完整性,有事需要对文件进行锁定。可以通过fcntl()函数对文件进行锁定和解锁。

\1. fcntl

1.1.功能描述:根据文件描述词来操作文件的特性。

1.2.用法:

int fcntl(int fd, int cmd);

int fcntl(int fd, int cmd, long arg);

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

fd:文件描述词。

cmd:操作命令。

arg:供命令使用的参数,是否需要arg参数跟cmd命令有关。

lock:锁信息。

2.读写锁实例

新建两个文件,源码如下2.1、2.2所示。

2.1.给文件加读锁

#include 

\#include 

\#include 

\#include 

\#include 

int main(int argc, const char * argv [ ])

{

int fd = open("test.c", O_RDONLY);

if (fd == -1)

{

perror("open failed:");

return -1;

}

struct stat sta;

fstat(fd,&sta);

struct flock lock;  

lock.l_len = sta.st_size;

lock.l_pid = getpid();

lock.l_start = 0;

lock.l_type = F_RDLCK;

lock.l_whence = SEEK_SET;

printf("进程pid: %d\n",lock.l_pid);

if(fcntl(fd,F_SETLK,&lock) == -1)

{

perror("fcntl fail ");

return -1;

}

else

{

printf("add read lock success!\n");

}

sleep(10);

close(fd);

return 0;

}

2.2.给文件加写锁

\#include 

\#include 

\#include 

\#include 

\#include 

int main(int argc, const char * argv [ ])

{

int fd = open("test.c", O_WRONLY);

if (fd == -1)

{

perror("open failed:");

return -1;

}

struct stat sta;

fstat(fd,&sta);

struct flock lock;  

lock.l_len = sta.st_size;

lock.l_pid = getpid();

lock.l_start = 0;

lock.l_type = F_WRLCK;

lock.l_whence = SEEK_SET;

printf("进程pid: %d\n",lock.l_pid);

while(fcntl(fd,F_SETLK,&lock) == -1 )

{

perror("fcntl:");

sleep(1);

struct flock lock_1;

lock_1 = lock;

lock_1.l_type = F_WRLCK;  //

fcntl(fd,F_GETLK,&lock_1);//获取文件锁状态,及加锁(lock_1.l_type)能否成功

switch(lock_1.l_type)

{

case F_RDLCK:

printf("检测到读锁 pid = %d \n",lock_1.l_pid);

break;

case F_WRLCK:

printf("检测到写锁 pid = %d \n",lock_1.l_pid);

break;

case F_UNLCK:

printf("检测到已解锁.pid = %d \n",lock_1.l_pid);

}

}

printf("写锁设置成功\n");

getchar();

close(fd);

return 0;

}


/*

注意:

Linux Security Scanner
Linux Security Scanner

Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...

下载

1、fcntl(fd,F_GETLK,&lock_1)中的lock_1必须进行初始化,并且lock_1.l_type必须设置为相应的锁,才能确定能否加锁成功,及不成功的原因。

2、GETLK时,fcntl先检测有没有能阻止本次加锁的锁,如果有,则覆盖flock结构体(lock_1)的信息。如果没有,则置lock_1.l_type 的类型为F_UNLCK。

*/

对于写锁(F_WRLCK 独占锁),只有一个进程可以在文件的任一特定区域上享有独占锁。

对于读锁(F_RDLCK 共享锁),许多不同的进程可以同时拥有文件上同一区域上的共享锁。为了拥有共享锁,文件必须以读或者读/写的方式打开。只要任一进程拥有共享锁,那么其他进程就无法再获得独占锁。

分别编译执行:

3.先执行读锁,再执行写锁。结果如下:

liu@ubuntu:~/learn/lrn_linux$ ./readlock.out 

进程pid: 16458

add read lock success!

liu@ubuntu:~/learn/lrn_linux$ ./writelock.out 

进程pid: 16459

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到读锁 pid = 16458 

fcntl:: Resource temporarily unavailable

检测到已解锁.pid = 16459 

写锁设置成功

可以看出,当文件被读锁占用时,无法添加写锁(独占锁)

4.先运行写锁,再运行读锁的话,结果如下:

liu@ubuntu:~/learn/lrn_linux$ ./writelock.out 

进程pid: 16349

写锁设置成功

liu@ubuntu:~/learn/lrn_linux$ ./readlock.out 

进程pid: 16350

fcntl fail : Resource temporarily unavailable

所以,加锁是成功的。

通过本文,你应该对 Linux 系统编程中使用 fcntl() 实现读写锁的方法有了一个基本的了解,知道了它的原理、用法和优缺点。你也应该明白了使用 fcntl() 实现读写锁的目的和影响,以及如何在 Linux 系统编程中正确地使用和配置 fcntl()。我们建议你在需要实现读写锁的场景中,使用 fcntl() 来实现你的目标。同时,我们也提醒你在使用 fcntl() 时要注意一些潜在的问题和挑战,如兼容性、可移植性、性能等。希望本文能够帮助你更好地使用 Linux 系统编程,让你在 Linux 下掌握 fcntl() 的技巧和优势。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

2025.06.09

5074

18

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

2025.07.04

5251

25

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6959

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

3325

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

4348

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2945

10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4538

6

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

2023.06.21

4350

4

如何安装LINUX
如何安装LINUX

本站专题提供如何安装LINUX的相关教程文章,还有相关的下载、课程,大家可以免费体验。

2023.06.29

3653

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

Buffalo框架快速入门指南
Buffalo框架快速入门指南

共0课时 | 0人学习

Valgrind支持平台说明
Valgrind支持平台说明

共0课时 | 0人学习