在共享内存中初始化 pthread 互斥锁

Posted

技术标签:

【中文标题】在共享内存中初始化 pthread 互斥锁【英文标题】:Initializing a pthread mutex in shared memory 【发布时间】:2010-11-01 12:47:16 【问题描述】:

我可以使用初始化器在静态内存中初始化互斥锁:

pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;

但是如何在共享内存中初始化一个,我必须与初始化变量分开分配内存?我可以做一个 memcpy() 吗?

pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
memcpy(&globalmutex, &mymutex, sizeof(mymutex);

我想我记得很久以前读过,当将互斥锁分配到保证初始化为零的内存中时,它不需要初始化——正是为了这种情况——但我找不到写下来的任何地方。这是真的吗?--我注意到 PTHREAD_MUTEX_INITIALIZER 在我的 redhat 系统上被定义为 0, 0, 0, 0, 0, 0, 0, 0 。

【问题讨论】:

【参考方案1】:

您需要在这里小心,并非所有实现都支持可以跨进程工作的互斥锁。

PThreads 本身通过使用进程共享属性来支持这一点,但是,如果您愿意,您将不会使用默认初始化程序。

相反,您需要在正确构造互斥体属性结构后使用pthread_mutex_init()

int pthread_mutex_init(
    pthread_mutex_t *mutex,
    const pthread_mutexattr_t *attr);

最好的办法是在共享内存中分配空间,然后将其转换为正确的类型并将其传递给init 函数。我认为这可能比在初始化后复制它更安全。

【讨论】:

如果这样做,如何防止每个进程初始化 mutext?过程1:初始化;过程1:锁定;过程2:初始化;我敬酒。 @John,如果您有线程初始化互斥锁(而不是创建线程之前的main),这将是完全相同的问题。我有个问题。您要跨进程保护什么资源?可能还有其他方法。 我使用 PTHREAD_MUTEX_INITIALIZER 来保证我的互斥体在任何处理开始之前只初始化一次。我正在编写可能同时在多个进程中运行的 CUDA(GPU 处理)代码,并且我想用锁保护 CudaMalloc 块,以便进程在可用时获取所有内存。我不希望三个进程失败——每个进程都有 40% 的所需内存。 我会考虑在您的一个进程中设置共享内存互斥锁,然后让它启动另外两个(如果可能的话)。正如我所说,即使您的 pthreads 实现支持跨进程互斥锁,默认状态也是进程私有的,所以我很确定您不能使用 PTHREAD_MUTEX_INITIALIZER。 很遗憾,我无法控制进程的启动。【参考方案2】:

我有一个类似的问题,我正在使用的一种方法是尝试使用(O_CREAT | O_RDWR | O_EXCL) 专门创建共享内存。如果创建成功,则在共享内存中初始化互斥锁。如果失败,请检查共享内存是否已经存在。如果共享内存存在,只需使用标志O_RDWR 打开它并映射到您的互斥体,但假设它已经由成功创建它的进程初始化。这是一些伪代码(POSIX + pthreads):

/* semaphore POST (block access from other processes) */
/* try to exclusively create */
int fd = shm_open (name, (O_CREAT | O_RDWR | O_EXCL), (S_IRUSR | S_IWUSR));
if (fd == -1) 
    /* failed creation */
    /* semaphore WAIT (wait until mutex initialized) */
    if (errno == EEXIST) 
        /* already exists, try to open */
        fd = shm_open (name, O_RDWR, (S_IRUSR | S_IWUSR));
        if (fd == -1) 
            /* check errors */
         else 
            /* optionally check shared data size with fstat */
            fstat () ...
            /* map */
            mmap () ...
        
     else 
        /* check create errors */
    
 else 
    /* successful creation! */
    /* truncate */
    ftruncate () ...
    /* map */
    mmap () ...
    /* initialize mutex */
    pthread_mutexattr_init () ...
    pthread_mutexattr_setpshared ( ... , PTHREAD_PROCESS_SHARED ) ...
    pthread_mutex_init () ...
    /* semaphore WAIT (wait until all processes are finished) */

此方法的一个问题是可能存在竞争条件,即另一个进程打开它并尝试在创建共享内存之后但在初始化互斥锁之前立即锁定互斥锁。我从未尝试过测试这种情况(这将很难实现) - 我没有使用推动这些限制的系统。但是,在这种情况下,信号量可能有助于在创建互斥体之前阻止访问。我在 cmets 中添加了信号量逻辑,但我希望得到有关它的反馈(信号量未实现或测试)。

编辑

经过一番思考,我意识到 IPC 信号量守卫作为互斥锁可能更好,然后我们必须递归地创建一个共享内存互斥锁,哈哈。但严肃地说,拥有一个单独管理保护互斥锁的创建、初始化和销毁​​的进程是可行的。

【讨论】:

我认为如果流程启动是定时/系统协调的,你的方法会很好地工作。在我支持的系统中,这种情况的一个变体有一个专用于分配器的进程,并且读取器都在尝试映射共享内存之前建立进程间通信 - 使用操作系统提供的消息传递功能。由于分配器在开始响应消息之前进行分配,因此对任何消息的响应都会告诉映射器内存应该可用。 @sage 谢谢你的评论,我已经改变了我的方法,有一个专用的分配器/主管进程以你描述的方式管理共享内存。这是确保可靠的无竞争和安全 IPC 映射的最佳方式。

以上是关于在共享内存中初始化 pthread 互斥锁的主要内容,如果未能解决你的问题,请参考以下文章

Linux C 多线程编程之互斥锁与条件变量实例详解

互斥锁- pthread_mutex

在 C/C++ 共享内存中等待和通知

如何为一组 pthread 共享互斥锁?

如果只有一个线程使用互斥锁,跨线程的共享内存会损坏吗?

仅读取共享内存时的互斥锁