如何在Linux和C中将文件用作互斥锁?

时间:2011-09-06 19:09:01

标签: c linux mutex

我有不同的进程同时访问Linux中的命名管道,我想让这个访问互斥。

我知道可以使用放置在共享内存区域中的互斥锁来实现这一点,但作为一种家庭作业,我有一些限制。

因此,我想到的是在文件上使用锁定原语来实现互斥;我做了一些尝试,但我无法让它发挥作用。

这是我试过的:

flock(lock_file, LOCK_EX)

// critic section

flock(lock_file, LOCK_UN)

不同的项目将使用不同的文件描述符,但引用相同的文件。 是否有可能实现这样的目标?你能提供一些例子。

3 个答案:

答案 0 :(得分:4)

标准锁文件技术在O_EXCL调用上使用open()等选项来尝试创建文件。使用锁存储进程的PID,以便确定进程是否仍然存在(使用kill()进行测试)。你必须担心并发 - 很多。

步骤:

  • 根据FIFO名称
  • 确定锁定文件的名称
  • 打开锁定文件(如果存在)
  • 检查是否存在使用它的进程
    • 如果存在其他进程,则它具有控制权(退出时出错或等待退出)
    • 如果缺少其他进程,请删除锁定文件
  • 此时,上次检查时锁文件不存在。
  • 尝试使用其他选项中的open()O_EXCL创建它。
  • 如果可行,您的流程会创建该文件 - 您有权继续。
  • 将PID写入文件;关闭它。
  • 打开FIFO - 使用它。
  • 完成后(atexit()?)删除锁定文件。

担心如果打开锁定文件并且没有读取PID会发生什么...是否是另一个进程刚刚创建它并且还没有将PID写入其中,或者在执行此操作之前它已经死了?可能最好退回 - 关闭文件并重试(可能在随机nanosleep()之后)。如果你多次获得空文件(比如说连续3个),则认为进程已经死了并删除了锁文件。

您可以考虑让拥有该文件的进程在FIFO打开时对文件保持建议锁定。如果没有锁,则该过程已经死亡。在打开文件和应用锁定之间仍有一个TOCTOU(检查时间,使用时间)窗口。

仔细查看系统上的open()手册页,了解是否还有其他选项可以帮助您。有时,进程使用目录(mkdir())而不是文件,因为即使root也无法创建给定目录名的第二个实例,但是如果知道如何在资源打开的情况下知道进程的PID,等

答案 1 :(得分:4)

我绝对建议使用实际的互斥锁(正如评论中所建议的那样);例如,pthread库提供an implementation。但是如果你想自己使用一个文件用于教育目的,我建议你看一下前一段时间发布的this answer,它描述了在Python中这样做的方法。转换为C,它应该看起来像这样(警告:未经测试的代码,使用风险自负;我的C也生锈):

// each instance of the process should have a different filename here
char* process_lockfile = "/path/to/hostname.pid.lock";
// all processes should have the same filename here
char* global_lockfile = "/path/to/lockfile";
// create the file if necessary (only once, at the beginning of each process)
FILE* f = fopen(process_lockfile, "w");
fprintf(f, "\n"); // or maybe write the hostname and pid
fclose(f);

// now, each time you have to lock the file:
int lock_acquired = 0;
while (!lock_acquired) {
    int r = link(process_lockfile, global_lockfile);
    if (r == 0) {
        lock_acquired = 1;
    }
    else {
        struct stat buf;
        stat(process_lockfile, &buf);
        lock_acquired = (buf.st_nlink == 2);
    }
}
// do your writing
unlink(global_lockfile);
lock_acquired = 0;

答案 2 :(得分:3)

您的示例与您使用flock (2)一样好(毕竟,这只是一个“建议”锁定(也就是说不是锁定) ,真的))。我的Mac OS X系统上的手册页有几个可能很重要的附带条件:

  

锁定在文件上,而不是文件描述符。也就是说,通过dup(2)或fork(2)复制的文件描述符不会导致a的多个实例        锁定,而是对单个锁的多个引用。如果一个进程对文件分支进行锁定并且子进程明确地解锁了该文件,那么        父母将失去锁定

  

阻止等待锁定的进程可能会被信号唤醒。

两者都提出了失败的方法。


//本来是评论,但我想引用一些长度的手册页