Linux(编程):多进程同步-文件锁
创始人
2024-05-29 16:53:00
0

文件锁又叫记录锁,他的作用是:当一个进程正在读或修改文件的某个部分是,可以通过文件锁阻止其他进程修改同一文件区。

不仅仅是文件,对于多进程间共享的资源,都可以通过文件锁进行同步。

文件锁所使用的接口函数为:

int fcntl(int fd, int cmd, struct flock *lock);/*其中cmd的可选值为:
cmd = F_GETLK,测试是否可以加锁,返回值仅对当前有效,无法包装后续的加锁或解锁一定成功
cmd = F_SETLK,设置锁(加锁或解锁),如果无法设置锁,该函数会立即返回一个EACCESS或EAGAIN错误,而不会阻塞
cmd = F_SETLKW, 阻塞设置一把锁,无法设置锁的时候,会阻塞直到该锁能够进行设置
*/

以下是对文件锁进行的封装:

//file_lock.h
#ifndef FILE_LOCK_H
#define FILE_LOCK_H#include 
#include 
#include 
#include 
#include 
using std::string;enum class FILE_LOCK_RES{OK = 0,FILE_OPEN_FAILED = 1,READ_LOCK_FAILED = 2,WRITE_LOCK_FAILED = 3,UNLOCK_FAILED = 4,CHECK_LOCK_FAILED = 5,CHECK_LOCK_READY = 6,CHECK_LOCK_BUSY = 7,
};class FileLock{
public:FileLock(const string& filePath);FILE_LOCK_RES readLock();FILE_LOCK_RES writeLock();FILE_LOCK_RES unlock();FILE_LOCK_RES checkReadLock(pid_t* pidinfo = nullptr);FILE_LOCK_RES checkWriteLock(pid_t* pidinfo = nullptr);~FileLock();
private:int m_fd;string m_filePath;void initFlock(struct flock& lock, short type, short whence, off_t start, off_t len);string getPrefix();
};#endif
//file_lock.cpp#include 
#include 
#include 
#include 
#include "file_lock.h"
using namespace std;FileLock::FileLock(const string& filePath):m_filePath(filePath)
{m_fd = open(m_filePath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);if(m_fd < 0){cout<<"file:"< 0){close(m_fd);m_fd = -1;}
}void FileLock::initFlock(struct flock& lock, short type, short whence, off_t start, off_t len)
{lock.l_type = type;lock.l_whence = whence;lock.l_start = start;lock.l_len = len;
}FILE_LOCK_RES FileLock::readLock()
{if(m_fd < 0){return FILE_LOCK_RES::FILE_OPEN_FAILED;}struct flock lock;initFlock(lock, F_RDLCK, SEEK_SET, 0, 0);if(fcntl(m_fd, F_SETLKW, &lock) != 0){cout<
//main.cpp
#include 
#include 
#include 
#include 
#include "file_lock.h"
using namespace std;int main()
{FileLock fl("./test_file_lock");fl.writeLock();fl.readLock();fl.unlock();fl.readLock();fl.unlock();return 0;
}
//CMakeLists.txt
cmake_minimum_required(VERSION 3.5)project(file_lock)add_executable(file_lock main.cpp file_lock.cpp)target_include_directories(file_lock PRIVATE ${CMAKE_SOURCE_DIR})
编译运行程序输出:
1678107928 pid:6427 file:./test_file_lock write lock ok
1678107928 pid:6427 file:./test_file_lock read lock ok
1678107928 pid:6427 file:./test_file_lock unlock ok
1678107928 pid:6427 file:./test_file_lock read lock ok
1678107928 pid:6427 file:./test_file_lock unlock ok
可以看出,同一个进程可以同时对文件已加锁区间进行多次加锁。

通过上面封装的类对以下几种具体的情况加以验证和说明:

  1. 加锁的进程结束后会自动释放锁

#include 
#include 
#include 
#include 
#include "file_lock.h"
using namespace std;string getPrefix()
{time_t time_now = time(NULL); pid_t pid = getpid();string prefix = to_string((unsigned long)time_now) + " pid:" + to_string((unsigned long)pid) + " ";return prefix;
}int main()
{pid_t pid = fork();if(pid == 0){//childcout< 0){//fathercout<
运行程序输出:
1678109358 pid:6583 father pid is 6583
1678109358 pid:6584 child pid is 6584
1678109358 pid:6584 file:./test_file_lock write lock ok
1678109360 pid:6583 file:./test_file_lock write lock ok
1678109360 pid:6583 file:./test_file_lock unlock ok
1678109362 pid:6583 child pid:6584 exit
  1. close文件描述符,加载在其上的锁也会自动释放:

#include 
#include 
#include 
#include 
#include "file_lock.h"
using namespace std;string getPrefix()
{time_t time_now = time(NULL); pid_t pid = getpid();string prefix = to_string((unsigned long)time_now) + " pid:" + to_string((unsigned long)pid) + " ";return prefix;
}void testFl()
{FileLock fl("./test_file_lock");fl.writeLock();
}int main()
{pid_t pid = fork();if(pid == 0){//childcout< 0){//fathercout<
运行程序输出:
1678109603 pid:6613 father pid is 6613
1678109603 pid:6614 child pid is 6614
1678109603 pid:6614 file:./test_file_lock write lock ok
1678109604 pid:6613 file:./test_file_lock write lock ok
1678109604 pid:6613 file:./test_file_lock unlock ok
1678109608 pid:6614 child exit
1678109608 pid:6613 wait child pid:6614 exit
  1. fork出的子进程不能继承父进程的锁:

#include 
#include 
#include 
#include 
#include "file_lock.h"
using namespace std;string getPrefix()
{time_t time_now = time(NULL); pid_t pid = getpid();string prefix = to_string((unsigned long)time_now) + " pid:" + to_string((unsigned long)pid) + " ";return prefix;
}int main()
{cout< 0){//fathersleep(2);fl.unlock();waitpid(pid, 0, 0);cout<
运行程序输出:
1678109969 pid:6669 father pid is 6669
1678109969 pid:6669 file:./test_file_lock write lock ok
1678109969 pid:6670 child pid is 6670
1678109971 pid:6669 file:./test_file_lock unlock ok
1678109971 pid:6670 file:./test_file_lock write lock ok
1678109976 pid:6670 file:./test_file_lock unlock ok
1678109976 pid:6670 child exit
1678109976 pid:6669 wait child pid:6670 exit
  1. 文件锁的状态可以进行检查:

#include 
#include 
#include 
#include 
#include "file_lock.h"
using namespace std;string getPrefix()
{time_t time_now = time(NULL); pid_t pid = getpid();string prefix = to_string((unsigned long)time_now) + " pid:" + to_string((unsigned long)pid) + " ";return prefix;
}int main()
{pid_t pid = fork();if(pid == 0){//childcout< 0){//fathercout<
运行程序输出:
1678110443 pid:6741 father pid is 6741
1678110443 pid:6741 file:./test_file_lock write lock ok
1678110443 pid:6742 child pid is 6742
1678110444 pid:6742 file:./test_file_lockread lock is busy by pid:6741
1678110444 pid:6742 lock is busy
1678110445 pid:6741 file:./test_file_lock unlock ok
1678110449 pid:6742 file:./test_file_lockread lock is ready
1678110449 pid:6742 lock is ready
1678110449 pid:6742 file:./test_file_lock write lock ok
1678110449 pid:6742 file:./test_file_lock unlock ok
1678110449 pid:6742 child exit
1678110449 pid:6741 wait child pid:6742 exit

另外需要注意的是:加锁时,进程必须对文件有相应的文件访问权限,即加读锁,该文件必须是读打开,加写锁时,该文件必须是写打开。

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...