zoukankan      html  css  js  c++  java
  • Linux 多进程锁的几种实现方案

    我们知道,多线程可以用多线程互斥量pthread_mutex_t实现线程之间上锁,那么多进程之间如何共享锁呢?

    1. 文件锁实现多进程锁

    由于文件锁是存放到位于内存的系统文件表中, 所有进程/线程可通过系统访问。如果不同进程使用同一文件锁(写锁/排他锁),当取得文件锁时,进程可继续执行;如果没有取得锁,则阻塞等待。而唯一标识该文件的是文件路径,因此,可以通过一个共同的文件路径,来实现多进程锁机制。
    参见文件锁的本质核心和原理 | CSDN

    关键点:
    1)创建/打开一个唯一路径的文件;
    2)P操作,取得文件的写锁(排他锁);V操作,释放文件的锁;

    static struct flock lock_it; /* 用于加锁的flock对象 */
    static struct unlock_it;     /* 用于解锁的flock对象 */
    static int lock_fd = -1; 
    
    void
    my_lock_init(char *pathname)
    {
        char lock_file[1024]; /* 存放文件名的临时缓存 */
        
        /* 由于mkstemp会修改参数的最后6个字符,为避免pathname是字符串常量,需要将字符串从pathname copy到临时缓存lock_file中,然后作为创建唯一临时文件的参数 */
        strncpy(lock_file, pathname, sizeof(lock_file));
        lock_fd = mkstemp(lock_file); /* 创建唯一的临时文件并打开 */
        
        unlink(lock_file); /* 删除指定文件名的文件,如果有进程打开了该文件,会在进程结束后所有指向该文件的描述符都关闭后删除文件。这样可以确保即使程序崩溃,临时文件也会完全消失 */
    
        /* 设置flock对象的写锁属性 */
        lock_it.l_type = F_WRLCK;
        lock_it.l_whence = SEEK_SET;
        lock_it.l_start = 0;
        lock_it.l_len = 0;
    
        /* 设置flock对象的解锁属性 */
        unlock_it.l_type = F_UNLCK;
        unlock_it.l_whence = SEEK_SET;
        unlock_it.l_start = 0;
        unlock_it.l_len = 0;
    }
    
    void
    my_lock_wait()
    {
        int rc;
        
        /* 取得写锁,如果阻塞等待时被中断唤醒,则继续恢复阻塞等待锁资源 */
        whilel ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) {
            if (errno == EINTR) continue;
            else err_sys("my_lock_wait fcntl error");  /* 如果没有调用my_lock_init就直接调用fcntl,将会失败 */
        }
    }
    
    void 
    my_lock_release()
    {
        if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0)
            err_sys("my_lock_release fcntl error");
    }
    

    2. 多线程锁实现多进程锁

    多线程之间天然共享内存/变量,而多进程各有自己的进程空间,它们之间是不共享数据的

    2个关键步骤
    1)互斥锁变量存放到共享内存;
    2)设置互斥锁变量的进程共享属性(PTHREAD_PROCESS_SHARED);

    static pthread_mutex_t *mptr; /* 互斥锁变量指针,互斥锁变量存放到共享内存 */
    
    /**
    * 多进程互斥锁变量初始化
    */
    void
    my_lock_init()
    {
        int fd;
        pthread_mutexattr_t mattr;
    
        /* 新建共享内存区域,但不映射到实际的普通文件 */
        fd = open("/dev/zero", O_RDWR, 0);
        if (fd < 0) err_sys("open error");
        mptr = mmap(0, sizeof(pthread_mutex_t), PORT_READ | PORT_WRITE, MAP_SHARED, fd, 0);
        if (mptr == MAP_FAILED) err_sys("mmap");
        if (close(fd)) err_sys("close error");
        
        pthread_mutexattr_init(&mattr);
        pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
        phtread_mutex_init(mptr, &mattr);
    }
    
    /**
    * 加锁
    */
    void
    my_lock_wait()
    {
      pthread_mutex_lock(mptr);
    }
    
    /**
    * 解锁
    */
    void 
    my_lock_release()
    {
        pthread_mutex_unlock(mptr);
    }
    

    对于符合4.4BSD的Linux系统,直接支持匿名内存映射,可以通过指定mmap的参数flag = MAP_ANON,fd = -1,offset被忽略.
    而上面将fd指向打开的/dev/zero,是更通用的做法,任何类Unix系统通常都支持。

    # ifdef MAP_ANON
    ptr = mmap(0, nchildren * sizeof(long), PORT_READ | PORT_WRITE, MAP_ANON | MAP_SHARED, -1 , 0);
    #else
    int fd;
    
    fd = open("/dev/zero", O_RDWR, 0);
    if (fd < 0)
        err_sys("open error");
    
    ptr = mmap(0, nchildren * sizeof(long), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    #endif
    
  • 相关阅读:
    实验
    ls -l 详解
    实验
    B
    2.02_Python网络爬虫分类及其原理
    2.01_Python网络爬虫概述
    DA_03_linux网络配置及其远程连接
    DA_01_linux_物理机局域网工作机制
    Hadoop_01_Apache Hadoop概述
    13_Redis_持久化
  • 原文地址:https://www.cnblogs.com/fortunely/p/14923945.html
Copyright © 2011-2022 走看看