进程间通信:文件锁

简介: int flock(int fd, int operation);其中,参数 fd 表示文件描述符;参数 operation 指定要进行的锁操作,该参数的取值有如下几种:LOCK_SH, LOCK_EX, LOCK_UN 和 LOCK_MANDLOCK_SH:表示要创建一个共享锁,...

 

int flock(int fd, int operation);

其中,参数 fd 表示文件描述符;参数 operation 指定要进行的锁操作,该参数的取值有如下几种:LOCK_SH, LOCK_EX, LOCK_UN 和 LOCK_MAND

  • LOCK_SH:表示要创建一个共享锁,在任意时间内,一个文件的共享锁可以被多个进程拥有
  • LOCK_EX:表示创建一个排他锁,在任意时间内,一个文件的排他锁只能被一个进程拥有
  • LOCK_UN:表示删除该进程创建的锁
  • LOCK_MAND: 它主要是用于共享模式强制锁,它可以与 LOCK_READ 或者 LOCK_WRITE 联合起来使用,从而表示是否允许并发的读操作或者并发的写操作(尽管在 flock() 的手册页中没有介绍 LOCK_MAND,但是阅读内核源代码就会发现,这在内核中已经实现了)

通常情况下,如果加锁请求不能被立即满足,那么系统调用 flock() 会阻塞当前进程。比如,进程想要请求一个排他锁,但此时,已经由其他进程获取了这个锁,那么该进程将会被阻塞。如果想要在没有获得这个排他锁的情况下不阻 塞该进程,可以将 LOCK_NB 和 LOCK_SH 或者 LOCK_EX 联合使用,那么系统就不会阻塞该进程。flock() 所加的锁会对整个文件起作用。

 

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

其中,参数 fd 表示文件描述符;参数 cmd 指定要进行的锁操作,由于 fcntl() 函数功能比较多,这里先介绍与文件锁相关的三个取值 F_GETLK、F_SETLK 以及 F_SETLKW。这三个值均与 flock 结构有关。

struct flock
{
short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
__off_t l_start; /* Offset where the lock begins. */
__off_t l_len; /* Size of the locked area; zero means until EOF. */
__pid_t l_pid; /* Process holding the lock. */
};

在 flock 结构中,l_type 用来指明创建的是共享锁还是排他锁,其取值有三种:F_RDLCK(共享锁)、F_WRLCK(排他锁)和F_UNLCK(删除之前建立的 锁);l_pid 指明了该锁的拥有者;l_whence、l_start 和l_end 这些字段指明了进程需要对文件的哪个区域进行加锁,这个区域是一个连续的字节集合。因此,进程可以对同一个文件的不同部分加不同的锁。l_whence 必须是 SEEK_SET、SEEK_CUR 或 SEEK_END 这几个值中的一个,它们分别对应着文件头、当前位置和文件尾。l_whence 定义了相对于 l_start 的偏移量,l_start 是从文件开始计算的。

可以执行的操作包括:

  • F_GETLK: 进程可以通过它来获取通过 fd 打开的那个文件的加锁信息。执行该操作时,lock 指向的结构中就保存了希望对文件加的锁(或者说要查询的锁)。如果确实存在这样一把锁,它阻止 lock 指向的 flock 结构所给出的锁描述符,则把现存的锁的信息写到 lock 指向的 flock 结构中,并将该锁拥有者的 PID 写入 l_pid 字段中,然后返回;否则,就将 lock 指向的 flock 结构中的 l_type 设置为 F_UNLCK,并保持 flock 结构中其他信息不变返回,而不会对该文件真正加锁。
  • F_SETLK:进程用它来对文件的某个区域进行加锁(l_type的值为 F_RDLCK 或 F_WRLCK)或者删除锁(l_type 的值为F_UNLCK),如果有其他锁阻止该锁被建立,那么 fcntl() 就出错返回
  • F_SETLKW:与 F_SETLK 类似,唯一不同的是,如果有其他锁阻止该锁被建立,则调用进程进入睡眠状态,等待该锁释放。一旦这个调用开始了等待,就只有在能够进行加锁或者收到信号时才会返回 。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/file.h>

#ifndef T_DESC
#define T_DESC(x, y)   (y)
#endif

#if T_DESC("fcntl", 1)

char *flock_name1 = "/tmp/flock1";
char *flock_name2 = "/tmp/flock2";
int flock_fd1;
int flock_fd2;

int read_lock(int fd)
{
    struct flock lock;  
    lock.l_start = 0;  
    lock.l_len = 0x10;  
    lock.l_type = F_RDLCK;  
    lock.l_whence = SEEK_SET;  
    int result = fcntl(fd, F_SETLK, &lock);  
    if(result<0){  
        perror("lockR:");  
    }  
    return result; 
}

int read_lock_wait(int fd)
{
    struct flock lock;  
    lock.l_start = 0;  
    lock.l_len = 0x10;  
    lock.l_type = F_RDLCK;  
    lock.l_whence = SEEK_SET;  
    return fcntl(fd, F_SETLKW, &lock);  
}

int write_lock(int fd)
{
    struct flock lock;  
    lock.l_start = 0;  
    lock.l_len = 0x10;  
    lock.l_type = F_WRLCK;  
    lock.l_whence = SEEK_SET;  
    return fcntl(fd, F_SETLK, &lock);
}

int write_lock_wait(int fd)
{
    struct flock lock;  
    lock.l_start = 0;  
    lock.l_len = 0x10;  
    lock.l_type = F_WRLCK;  
    lock.l_whence = SEEK_SET;  
    return fcntl(fd, F_SETLKW, &lock);  
}

int file_unlock(int fd)
{
    struct flock lock;  
    lock.l_start = 0;  
    lock.l_len = 0x10;  
    lock.l_type = F_UNLCK;  
    lock.l_whence = SEEK_SET;  
    return fcntl(fd, F_SETLK, &lock);  
}
#endif

#if T_DESC("flock", 1)

#endif


#if T_DESC("tu", 1)

void thread_11(void)  
{  
    int i;  
    for(i=0; i<100; i++)  {
        write_lock(flock_fd1);
        printf("This is pthread_111...");  
        sleep(2);  
        printf("111.\n");
        file_unlock(flock_fd1);
        sleep(1);
    }  
    pthread_exit(0);  
}  
  
void thread_12(void)  
{  
    int i;  
    for(i=0; i<100; i++) {
        write_lock(flock_fd2);
        printf("This is pthread_222...");  
        sleep(2);  
        printf("222.\n");
        file_unlock(flock_fd1);
        sleep(1);  
    }  
    pthread_exit(0);  
}  

void thread_21(void)  
{  
    int i;  
    for(i=0; i<100; i++)  {
        flock(flock_fd1, LOCK_EX);
        printf("This is pthread_111...");  
        sleep(2);  
        printf("111.\n");
        flock(flock_fd1, LOCK_UN);
        sleep(1);  
    }  
    pthread_exit(0);  
}  
  
void thread_22(void)  
{  
    int i;  
    for(i=0; i<100; i++) {
        flock(flock_fd1, LOCK_EX);
        printf("This is pthread_222...");  
        sleep(2);  
        printf("222.\n");
        flock(flock_fd1, LOCK_UN);
        sleep(1);  
    }  
    pthread_exit(0);  
}  

int tu1_proc(int tu_id)  
{  
    pthread_t id_1,id_2;  
    int fd,ret;  
    int param;

    flock_fd1 = open(flock_name1, O_RDWR| O_CREAT, 0600);
    if (flock_fd1 < 0) return -1;
    
    flock_fd2 = open(flock_name2, O_RDWR| O_CREAT, 0600);
    if (flock_fd2 < 0) return -1;

    if (tu_id == 1) {
        ret = pthread_create(&id_1, NULL, (void *)thread_11, NULL);  
    } else {
        ret = pthread_create(&id_2, NULL, (void *)thread_12, NULL);  
    }
    if(ret != 0)  
    {  
        printf("Create pthread error!\n");  
        return -1;  
    }  
    
    /*等待线程结束*/  
    if (tu_id == 1) {
        pthread_join(id_1, NULL);  
    } else {
        pthread_join(id_2, NULL);  
    }

    close(flock_fd1);
    close(flock_fd2);
    
    return 0;  
}  

#endif

#if T_DESC("global", 1)
void usage()
{
    printf("\n Usage: <cmd> <tu> <p1> <...>");
    printf("\n   1 -- create task 1");
    printf("\n   2 -- create task 2");
    printf("\n");
}

int main(int argc, char **argv)
{
    int ret;
    int tu_id;
    
    if(argc < 2) {
        usage();
        return 0;
    }

    tu_id = atoi(argv[1]);
    if (tu_id < 1 || tu_id > 2)  {
        usage();
        return 0;
    }
    
    ret = tu1_proc(tu_id);
    return ret;
}
#endif

#if T_DESC("readme", 1)
/*
1, how to compile 
gcc -o flock.out flock.c -lpthread

*/
#endif

 

目录
相关文章
|
26天前
|
Python
多进程同步之文件锁
【10月更文挑战第16天】文件锁是一种常用的多进程同步机制,它可以用于确保多个进程在访问共享资源时的互斥性。在使用文件锁时,需要注意锁的粒度、释放、竞争和性能等问题。通过合理使用文件锁,可以提高多进程程序的正确性和性能
|
4月前
FileLock 多进程文件锁
FileLock 多进程文件锁
39 0
5进程间锁:进程间pthread_mutex,文件锁
 1进程间pthread_mutex A依赖的头文件 #include&lt;pthread.h&gt; B函数声明 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
1281 0
|
6月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
129 13
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
177 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
4月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
5月前
|
存储 缓存 安全
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
171 1
|
5月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
107 2
|
5月前
|
SQL 自然语言处理 网络协议
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
193 1

热门文章

最新文章

相关实验场景

更多
下一篇
无影云桌面