共享内存中的条件变量-此代码符合POSIX吗? [英] Condition Variable in Shared Memory - is this code POSIX-conformant?

查看:90
本文介绍了共享内存中的条件变量-此代码符合POSIX吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

POSIX标准是否允许命名共享存储块包含互斥量和条件变量?

Does the POSIX standard allow a named shared memory block to contain a mutex and condition variable?

我们一直在尝试使用互斥量和条件变量来同步 LynuxWorks LynxOS-SE系统(符合POSIX).

We've been trying to use a mutex and condition variable to synchronise access to named shared memory by two processes on a LynuxWorks LynxOS-SE system (POSIX-conformant).

一个共享内存块称为"/sync",其中包含互斥锁和条件变量,另一个共享内存块是"/data",其中包含我们正在同步访问的实际数据.

One shared memory block is called "/sync" and contains the mutex and condition variable, the other is "/data" and contains the actual data we are syncing access to.

如果两个进程都不以完全相同的顺序执行mmap()调用,或者两个进程在其他进程中相互映射,则我们发现pthread_cond_signal()失败. em>一块共享内存,然后再映射"/sync"内存.

We're seeing failures from pthread_cond_signal() if both processes don't perform the mmap() calls in exactly the same order, or if one process mmaps in some other piece of shared memory before it mmaps the "/sync" memory.

这个示例代码大约是我能做到的那么短:

This example code is about as short as I can make it:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <iostream>
#include <string>
using namespace std;

static const string shm_name_sync("/sync");
static const string shm_name_data("/data");

struct shared_memory_sync
{
    pthread_mutex_t mutex;
    pthread_cond_t condition;
};

struct shared_memory_data
{
    int a;
    int b;
};


//Create 2 shared memory objects
// - sync contains 2 shared synchronisation objects (mutex and condition)
// - data not important 
void create()
{
    // Create and map 'sync' shared memory
    int fd_sync = shm_open(shm_name_sync.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
    ftruncate(fd_sync, sizeof(shared_memory_sync));
    void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
    shared_memory_sync* p_sync = static_cast<shared_memory_sync*> (addr_sync);

    // init the cond and mutex
    pthread_condattr_t cond_attr;
    pthread_condattr_init(&cond_attr);
    pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&(p_sync->condition), &cond_attr);
    pthread_condattr_destroy(&cond_attr);

    pthread_mutexattr_t m_attr;
    pthread_mutexattr_init(&m_attr);
    pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&(p_sync->mutex), &m_attr);
    pthread_mutexattr_destroy(&m_attr);

    // Create the 'data' shared memory   
    int fd_data = shm_open(shm_name_data.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
    ftruncate(fd_data, sizeof(shared_memory_data));

    void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
    shared_memory_data* p_data = static_cast<shared_memory_data*> (addr_data);

    // Run the second process while it sleeps here.
    sleep(10);

    int res = pthread_cond_signal(&(p_sync->condition));
    assert(res==0);  // <--- !!!THIS ASSERT WILL FAIL ON LYNXOS!!!

    munmap(addr_sync, sizeof(shared_memory_sync));
    shm_unlink(shm_name_sync.c_str());
    munmap(addr_data, sizeof(shared_memory_data));
    shm_unlink(shm_name_data.c_str());
}

//Open the same 2 shared memory objects but in reverse order
// - data
// - sync 
void open()
{
    sleep(2);
    int fd_data = shm_open(shm_name_data.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
    void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
    shared_memory_data* p_data = static_cast<shared_memory_data*> (addr_data);

    int fd_sync = shm_open(shm_name_sync.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
    void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
    shared_memory_sync* p_sync = static_cast<shared_memory_sync*> (addr_sync);

    // Wait on the condvar
    pthread_mutex_lock(&(p_sync->mutex));
    pthread_cond_wait(&(p_sync->condition), &(p_sync->mutex));
    pthread_mutex_unlock(&(p_sync->mutex));

    munmap(addr_sync, sizeof(shared_memory_sync));
    munmap(addr_data, sizeof(shared_memory_data));
}

int main(int argc, char** argv) 
{
    if(argc>1)
    {
        open(); 
    }
    else
    {
        create();
    }

    return (0);
}

在不使用args的情况下运行此程序,然后在使用args的另一个副本中运行,第一个副本将在断言pthread_cond_signal()的断言中失败. 但是,在"/data"之前将open()函数的顺序更改为mmap() "/sync内存,一切都将正常工作.

Run this program with no args, then another copy with args, and the first one will fail at the assert checking the pthread_cond_signal(). But change the order of the open() function to mmap() the "/sync" memory before the "/data" and it will all work fine.

在我看来,这似乎是LynxOS中的一个主要错误,但是LynuxWorks声称POSIX标准未涵盖以这种方式在已命名共享内存中使用互斥锁和条件变量,因此他们对此并不感兴趣.

This seems like a major bug in LynxOS to me, but LynuxWorks claim that using mutex and condition variable within named shared memory in this way is not covered by the POSIX standard, so they are not interested.

谁能确定此代码是否确实违反了POSIX?
还是有人有说服力的文档证明它符合POSIX?

Can anyone determine if this code does actually violate POSIX?
Or does anyone have any convincing documentation that it is POSIX compliant?

编辑:我们知道PTHREAD_PROCESS_SHARED是POSIX,并且受LynxOS支持.争论的领域是是否可以在已命名的共享内存中使用互斥锁和信号量(如我们所做的那样),或者POSIX仅在一个进程创建并映射共享内存然后分叉第二个进程时才允许使用它们.

Edit: we know that PTHREAD_PROCESS_SHARED is POSIX and is supported by LynxOS. The area of contention is whether mutexes and semaphores can be used within named shared memory (as we have done) or if POSIX only allows them to be used when one process creates and mmaps the shared memory and then forks the second process.

推荐答案

我可以轻松地了解如何在操作系统级别上实现PTHREAD_PROCESS_SHARED的技巧(例如,似乎不是rwlocks,但MacOS却没有).但是仅仅阅读标准,您似乎就有理由了.

I can easily see how PTHREAD_PROCESS_SHARED can be tricky to implement on the OS-level (e.g. MacOS doesn't, except for rwlocks it seems). But just from reading the standard, you seem to have a case.

为完整起见,您可能需要在 sysconf(_SC_THREAD_PROCESS_SHARED)和* _setpshared()函数的返回值调用—也许还有另一个惊喜"在等着你(但是我从注释中可以看到,您已经检查了SHARED是否确实受支持).

For completeness, you might want to assert on sysconf(_SC_THREAD_PROCESS_SHARED) and the return value of the *_setpshared() function calls— maybe there's another "surprise" waiting for you (but I can see from the comments that you already checked that SHARED is actually supported).

@JesperE:您可能想参考OpenGroup上的 API文档而不是HP文档.

@JesperE: you might want to refer to the API docs at the OpenGroup instead of the HP docs.

这篇关于共享内存中的条件变量-此代码符合POSIX吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆