posix:放弃进程间锁,有没有更好的方法?

时间:2017-03-04 21:21:18

标签: multithreading process locking posix

我在AIX上进行编码,但是寻找一般的&nbsp解决方案,理想情况下是posix兼容。无法在C ++ 11或更高版本中使用任何内容。

我与来自许多进程的许多线程共享内存。共享内存中的数据必须保持自洽,所以我需要一个锁,让每个人轮流使用。

使用锁进行崩溃是一件事,所以我必须能够检测到一个废弃的锁,修复(也就是重置)数据,然后继续前进。扭曲:通过等待一段固定的时间来决定锁定是不可行的。

全局互斥(生活在共享内存中或命名)似乎不是解决方案。没有遗弃的检测机制(时间除外),即使这样,你也不能删除和改造互斥体而不会冒未定义的行为风险。

所以我选择了lockf()和一个忙标志 - 获取文件锁,在共享内存中设置标志,做东西,取消设置标志,放下锁。在拥有锁的崩溃中,锁被自动删除,下一个获得它的人可以看到忙碌标志仍然设置,并且知道他必须清理一团糟。

这不起作用 - 因为lockf()会将线程与其他进程保持一致,但它对您自己进程中的其他线程有特殊的语义。它让他们通过未经检查。

最后,我想出了一个两步解决方案 - 本地(线程)互斥锁和文件锁。首先获取本地互斥;现在你是进行下一步的唯一线程,即lockf()。 lockf()反过来保证你是唯一的进程,所以现在你可以设置忙标志并完成工作。要解锁,请按相反顺序执行:清除忙标志,删除文件锁定,删除互斥锁。在崩溃中,当进程执行时,本地互斥锁消失,因此它是无害的。

工作正常。我讨厌它。使用这样嵌套的两个锁会让我感觉很贵,并且在代码中需要一页评论来解释。 (我的下一个代码审查将很有趣)。我觉得我错过了一个更好的解决方案。它是什么?

编辑:@Matt我可能不清楚。忙碌的旗帜不是锁定机制的一部分;它指示某个进程何时成功获得锁定。如果在获取锁之后,您看到busy标志已经设置,则表示其他进程已获得锁定然后崩溃,从而使共享内存处于写入状态不完整状态。在这种情况下,现在拥有锁的线程获得将共享存储器重新初始化为可用状态的工作。我可能应该称之为" memoryBeingModified"标志。

没有变化" tryLock"是允许的。在这个应用程序中,轮询绝对是不可能的。需要修改共享内存的线程可能只会阻塞锁(永远不会持有很长时间),并且只要锁具可用就必须立即轮流。他们必须经历最小的延迟。

2 个答案:

答案 0 :(得分:0)

你可以

//always returns true unless something horrible happened
bool lock()
{
    if (pthread_mutex_lock(&local_mutex)==0)
    {
        if (lockf(global_fd, F_LOCK, 0))
            return true;
        pthread_mutex_unlock(&local_mutex);
    }
    return false;
}

void unlock()
{
    lockf(global_fd, F_ULOCK, 0);
    pthread_mutex_unlock(&local_mutex);
}

对我来说这看起来非常简单,使用2级锁定我感觉不太好 - pthread_mutex非常快,几乎不消耗资源。

答案 1 :(得分:0)

简单的答案是,没有好的解决方案。在AIX上,出于完全没有理由,lockf的运行速度非常慢。但是共享内存中的互斥锁虽然在任何平台上都非常快,但是却很脆弱(任何人在持有锁的情况下都可能崩溃,并且无法恢复。)posix定义了一个很好的选择:“该互斥锁由线程/进程持有,死亡”,但即使这样,即使没有这样的错误代码,也无法修复并继续。与多个读取器和写入器使用共享内存仍然是狂野的西部。