我有一个多线程进程,其中一个文件由多个线程共享(读取和写入)。有什么方法线程可以锁定一个文件段,以便其他线程无法访问它?
我试过fcntl(fd, F_SETLKW, &flock)
,但是这个锁仅适用于进程,而不适用于线程(锁在进程中的所有线程之间共享)。
答案 0 :(得分:2)
是 - 但没有相同的机制。你必须使用类似pthread互斥的东西,并自己跟踪簿记。
如何使这项工作的可能纲要
发布流程级互斥
为进程抓取fnctl锁(如有必要)
释放fnctl锁以允许其他进程使用该段(如有必要)
再次等待进程级别簿结构互斥(如果你可以原子地将其标记为未使用,则可能没有必要)
答案 1 :(得分:1)
没有。您询问的区域锁定功能具有令人惊讶的语义,并且由于它是由POSIX控制的,因此没有进一步开发。 (实际上,这是Kirk McKusick首选的POSIX错误示例。)如果Linux中存在非POSIX字节范围锁定工具,我找不到它。
在这里讨论了多线程世界中POSIX字节范围锁定的问题:http://www.samba.org/samba/news/articles/low_point/tale_two_stds_os2.html。
但是,如果您只关心一个进程中的线程,则可以使用信号量构建自己的区域锁定。例如:
#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);
}
警告:代码编译但我还没有测试过它。
答案 2 :(得分:0)
如果您不需要在不同进程之间进行文件锁定,请避免使用文件锁(这是POSIX API设计最糟糕的部分之一),只使用互斥锁或其他共享内存并发原语。
答案 3 :(得分:0)
有两种方法可以做到:
使用Mutex在同一进程中的线程中获取记录锁定。获取锁之后,进程中的任何其他线程都会阻止映射尝试获取锁的文件,直到锁被释放为止。(Linux中可用的最简单且最直接的解决方案)。
共享内存或内存映射文件中的信号量和互斥量。