Linux线程中的文件段/节/记录锁

Linux线程中的文件段/节/记录锁,linux,c,locking,concurrency,multithreading,Linux,C,Locking,Concurrency,Multithreading,我有一个多线程进程,其中一个文件由多个线程共享(读写)。一个线程是否有办法锁定一个文件段,使其他线程无法访问它? 我已经尝试过fcntl(fd、F_SETLKW和flock),但是这个锁只适用于进程,而不适用于线程(一个进程中的所有线程都共享一个锁)。如果不同进程之间不需要文件锁,请避免使用文件锁(这是POSIXAPI中设计最差的部分之一)只需使用互斥锁或其他共享内存并发原语。如果不同进程之间不需要文件锁,请避免使用文件锁(这是POSIX API设计最差的部分之一),只需使用互斥锁或其他共享内存

我有一个多线程进程,其中一个文件由多个线程共享(读写)。一个线程是否有办法锁定一个文件段,使其他线程无法访问它?
我已经尝试过
fcntl(fd、F_SETLKW和flock)
,但是这个锁只适用于进程,而不适用于线程(一个进程中的所有线程都共享一个锁)。

如果不同进程之间不需要文件锁,请避免使用文件锁(这是POSIXAPI中设计最差的部分之一)只需使用互斥锁或其他共享内存并发原语。

如果不同进程之间不需要文件锁,请避免使用文件锁(这是POSIX API设计最差的部分之一),只需使用互斥锁或其他共享内存并发原语。

有两种方法可以做到这一点:

  • 使用互斥锁在同一进程内的线程中获取记录的锁。一旦获得了锁,进程中的任何其他线程(映射试图获取锁的文件)都将被阻止,直到释放锁为止(最好是Linux中唯一最简单的解决方案)

  • 共享内存或内存映射文件上的信号量和互斥量


  • 有两种方法可以做到这一点:

  • 使用互斥锁在同一进程内的线程中获取记录的锁。一旦获得了锁,进程中的任何其他线程(映射试图获取锁的文件)都将被阻止,直到释放锁为止(最好是Linux中唯一最简单的解决方案)

  • 共享内存或内存映射文件上的信号量和互斥量


  • 是-但不是用相同的机制。您必须使用pthread互斥体之类的东西,并自己记录簿记

    如何使这项工作可行的大纲

    • 等待并在簿记结构上声明进程级互斥
      • 确保进程中没有其他线程试图使用该段
      • 将自己标记为使用文件段
    • 释放进程级互斥锁

    • 抓取过程的fnctl锁(如有必要)

    • 做你的写作
    • 释放fnctl锁以允许其他进程使用该段(如有必要)

    • 在进程级簿记结构互斥体上再次等待(如果您可以以原子方式将其标记为未使用,则可能不需要)

      • 在流程中将段标记为未使用
    • 释放进程级互斥

    是-但不是使用相同的机制。您必须使用pthread互斥体之类的东西,并自己记录簿记

    如何使这项工作可行的大纲

    • 等待并在簿记结构上声明进程级互斥
      • 确保进程中没有其他线程试图使用该段
      • 将自己标记为使用文件段
    • 释放进程级互斥锁

    • 抓取过程的fnctl锁(如有必要)

    • 做你的写作
    • 释放fnctl锁以允许其他进程使用该段(如有必要)

    • 在进程级簿记结构互斥体上再次等待(如果您可以以原子方式将其标记为未使用,则可能不需要)

      • 在流程中将段标记为未使用
    • 释放进程级互斥

    否。您所询问的区域锁定功能具有令人惊讶的语义,由于它由POSIX控制,因此没有进一步开发。(事实上,这是柯克·麦库西克(Kirk McKusick)关于POSIX错误的首选例子。)如果Linux中有非POSIX字节范围锁功能,我就找不到它

    这里讨论了多线程世界中POSIX字节范围锁定的问题:

    但是,如果您只关心一个进程中的线程,那么可以使用信号量构建自己的区域锁定。例如:

    #include <stdbool.h>
    #include <pthread.h>
    #include <sys/types.h>
    
    // A record indicating an active lock.
    struct threadlock {
      int fd;  // or -1 for unused entries.
      off_t start;
      off_t length;
    };
    
    // A table of all active locks (and the unused entries).
    static struct threadlock all_locks[100];
    
    // Mutex housekeeping.
    static pthread_mutex_t mutex;
    static pthread_cond_t some_lock_released;
    static pthread_once_t once_control = PTHREAD_ONCE_INIT;
    static void threadlock_init(void) {
      for (int i = 0; i < sizeof(all_locks)/sizeof(all_locks[0]); ++i)
        all_locks[i].fd = -1;
      pthread_mutex_init(&mutex, (pthread_mutexattr_t *)0);
      pthread_cond_init(&some_lock_released, (pthread_condattr_t *)0);
    }
    
    // True iff the given region overlaps one that is already locked.
    static bool region_overlaps_lock(int fd, off_t start, off_t length) {
      for (int i = 0; i < sizeof(all_locks)/sizeof(all_locks[0]); ++i) {
        const struct threadlock *t = &all_locks[i];
        if (t->fd == fd &&
            t->start < start + length &&
            start < t->start + t->length)
          return true;
      }
      return false;
    }
    
    // Returns a pointer to an unused entry, or NULL if there isn't one.
    static struct threadlock *find_unused_entry(void) {
      for (int i = 0; i < sizeof(all_locks)/sizeof(all_locks[0]); ++i) {
        if (-1 == all_locks[i].fd)
          return &all_locks[i];
      }
      return 0;
    }
    
    // True iff the lock table is full.
    static inline bool too_many_locks(void) {
      return 0 == find_unused_entry();
    }
    
    // Wait until no thread has a lock for the given region
    // [start, start+end) of the given file descriptor, and then lock
    // the region. Keep the return value for threadunlock.
    // Warning: if you open two file descriptors on the same file
    // (including hard links to the same file), this function will fail
    // to notice that they're the same file, and it will happily hand out
    // two locks for the same region.
    struct threadlock *threadlock(int fd, off_t start, off_t length) {
      pthread_once(&once_control, &threadlock_init);
      pthread_mutex_lock(&mutex);
    
      while (region_overlaps_lock(fd, start, length) || too_many_locks())
        pthread_cond_wait(&some_lock_released, &mutex);
    
      struct threadlock *newlock = find_unused_entry();
      newlock->fd = fd;
      newlock->start = start;
      newlock->length = length;
    
      pthread_mutex_unlock(&mutex);
      return newlock;
    }
    
    // Unlocks a region locked by threadlock.
    void threadunlock(struct threadlock *what_threadlock_returned) {
      pthread_mutex_lock(&mutex);
    
      what_threadlock_returned->fd = -1;
      pthread_cond_broadcast(&some_lock_released);
    
      pthread_mutex_unlock(&mutex);
    }
    
    #包括
    #包括
    #包括
    //一种指示活动锁的记录。
    结构螺纹锁{
    int fd;//或-1表示未使用的条目。
    关闭启动;
    离体长度;
    };
    //所有活动锁(和未使用项)的表。
    静态结构线程锁所有_锁[100];
    //互斥管理。
    静态pthread_mutex_t mutex;
    静态pthread条件下释放一些锁;
    静态pthread_once_t once_control=pthread_once_INIT;
    静态void螺纹锁紧_init(void){
    对于(int i=0;ifd==fd&&
    t->开始<开始+长度&&
    开始开始+t->长度)
    返回true;
    }
    返回false;
    }
    //返回指向未使用项的指针,如果没有,则返回NULL。
    静态结构线程锁*查找未使用项(无效){
    对于(int i=0;i