【问题标题】:Mutex Shared between processes not working进程之间共享的互斥锁不起作用
【发布时间】:2021-07-28 01:28:16
【问题描述】:

我正在尝试在进程之间创建一个简单的共享互斥锁。这个想法是我将运行相同的可执行文件两次以创建两个进程,第一个进程应该创建一个共享互斥锁并将其锁定并休眠一段时间,同时另一个进程应该发现共享互斥锁被锁定并应该报告相同.为此,我编写了以下代码 -

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MYMUTEX "/mymutex"

int main(int argc, char* argv[])
{
    pthread_cond_t *cond;
    pthread_mutex_t *mutex;
    int cond_id, mutex_id;
    int mode = S_IRWXU | S_IRWXG;
    /* mutex */
    mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR, mode);
    printf("Mutex Id : %d\n", mutex_id);
    if (mutex_id < 0) {
        printf("shm_open failed\n");
        return -1;
    }
    if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
        printf("ftruncate failed\n");
        return -1;
    }
    mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
    if (mutex == MAP_FAILED) {
        printf("mmap failed\n");
        return -1;
    }
    printf("Mutex : %p\n", mutex);
    pthread_mutexattr_t mattr;
    pthread_mutexattr_init(&mattr);
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(mutex, &mattr);
    pthread_mutexattr_destroy(&mattr);

    if (pthread_mutex_trylock(mutex)) {
        printf("Cannot acquire Lock. Some instance might be already running\n");
    } else {
        printf("Acquired Lock now sleeping...\n");
        sleep(25);
        pthread_mutex_unlock(mutex);
        pthread_mutex_destroy(mutex);
        shm_unlink(MYMUTEX);
    }
    return 0;
}

据我所知,创建进程之间共享的互斥体,它应该映射到共享内存,并且应该设置属性 PTHREAD_PROCESS_SHARED。但是当我从两个单独的控制台运行程序时得到的结果是 -

控制台 1:

[gbose@seadev:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7faf2c57a000
Acquired Lock now sleeping...

控制台 2:

[gbose@seadev20:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f6d5766a000
Acquired Lock now sleeping...

我在这里缺少什么?我的预感是同时初始化互斥锁是这种意外行为的根本原因 - 如果这是正确的,那么还应该做些什么来检查互斥锁是否已经初始化?

更新:处理共享内存文件已经存在的情况,根据@Shawn 的评论添加 O_EXCL 但我仍然看到 mmap() 返回的内存地址是一个新地址粘贴在控制台输出上方。

    mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR | O_EXCL, mode);
    if (mutex_id < 0) {
        mutex_id = shm_open(MYMUTEX, O_RDWR, mode);
    } else {
        if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
            printf("ftruncate failed\n");
            return -1;
        }
    }

【问题讨论】:

  • 只有一个进程应该创建共享内存并初始化互斥锁(并在最后清理)。另一个应该映射共享内存并使用互斥锁。
  • 在这种情况下,计数为 1 的共享信号量更容易使用,imo。
  • @Shawn 谢谢!但是我将 shm_open 与 O_CREATE 一起使用,所以不应该自动处理如果共享内存对象已经存在然后不再创建一个的情况吗?那么 mmap 部分保持不变......如果我错了,请纠正我
  • 即使共享内存存在,它也会继续重新初始化互斥体。您可以使用涉及添加O_EXCL 的逻辑,如果成功则进行初始化,如果失败则打开现有的。
  • 尝试在没有O_CREAT的情况下再次打开它。

标签: c linux synchronization pthreads mutex


【解决方案1】:

感谢@Shawn 指出首先检查共享内存是否存在。检查共享内存对象是否已经存在,如果存在则不再初始化互斥锁。总结是如果我们重新初始化一个互斥锁,那么它的锁信息就会被覆盖,因此它不起作用。

    mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR | O_EXCL, mode);
    if (mutex_id < 0) {
        mutex_id = shm_open(MYMUTEX, O_RDWR, mode);
        mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
        if (mutex == MAP_FAILED) {
            printf("mmap failed\n");
            return -1;
        }
    } else {
        if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
            printf("ftruncate failed\n");
            return -1;
        }
        mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
        if (mutex == MAP_FAILED) {
            printf("mmap failed\n");
            return -1;
        }
        pthread_mutexattr_t mattr;
        pthread_mutexattr_init(&mattr);
        pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(mutex, &mattr);
        pthread_mutexattr_destroy(&mattr);
    }
    printf("Mutex Id : %d\n", mutex_id);
    printf("Mutex : %p\n", mutex);

    if (pthread_mutex_trylock(mutex)) {
        printf("Cannot acquire Lock. Some instance might be already running\n");
    } else {
        printf("Acquired Lock now sleeping...\n");
        sleep(25);
        pthread_mutex_unlock(mutex);
        pthread_mutex_destroy(mutex);
        shm_unlink(MYMUTEX);
    }

控制台 1

[gbose@seadev:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f3cd591c000
Acquired Lock now sleeping...

控制台 2

[gbose@seadev2:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f09db159000
Cannot acquire Lock. Some instance might be already running

【讨论】:

  • 明确地说,您仍然有竞争条件。进程 P2 可能会在 P1 专门创建它之后立即将刚刚创建的内存 (shm_open(..., O_EXCL...)) 设置为 openmmaptrylock,但是 之前 P1 已将内存初始化为共享互斥体。
  • 没错。你如何建议克服这种竞争条件?使用条件变量?
  • 这实际上不是一个简单的问题。我鼓励你尝试一个解决方案,也许可以提出一个新问题。
猜你喜欢
  • 1970-01-01
  • 2021-10-10
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 1970-01-01
  • 2017-07-26
  • 2013-11-24
相关资源
最近更新 更多