Gra*_*amS 5 unix posix ipc shared-memory lynxos
POSIX标准是否允许命名共享内存块包含互斥锁和条件变量?
我们一直在尝试使用互斥和条件变量来同步对LynuxWorks LynxOS-SE系统(POSIX-conformant)上的两个进程对命名共享内存的访问.
调用一个共享内存块"/sync"并包含互斥锁和条件变量,另一个是"/data"并包含我们同步访问的实际数据.
pthread_cond_signal()如果两个进程都没有mmap()以完全相同的顺序执行调用,或者如果一个进程在映射内存之前在某个其他共享内存中进行mmaps,我们就会看到失败"/sync".
这个示例代码与我可以做的一样短:
#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);
}
Run Code Online (Sandbox Code Playgroud)
运行这个程序没有args,然后是另一个带args的副本,第一个将在断言检查时失败pthread_cond_signal().但改变的顺序open()功能,mmap()在"/sync之前的"记忆"/data",它都将正常工作.
这似乎是LynxOS中的一个主要错误,但是LynuxWorks声称在这个方式中使用这种方式在命名共享内存中使用互斥和条件变量不在POSIX标准中,所以他们不感兴趣.
任何人都可以确定此代码是否确实违反了POSIX?
或者有没有人有任何令人信服的文件证明它符合POSIX标准?
编辑:我们知道这PTHREAD_PROCESS_SHARED是POSIX并得到LynxOS的支持.争用的范围是可以在命名共享内存中使用互斥锁和信号量(正如我们所做的那样),或者当一个进程创建并映射共享内存然后分叉第二个进程时,POSIX只允许使用它们.
该pthread_mutexattr_setpshared函数可用于允许任何有权访问该内存的线程访问共享内存中的 pthread 互斥锁,甚至是不同进程中的线程。根据此链接,pthread_mutex_setpshared符合 POSIX P1003.1c。(条件变量也是如此,请参阅pthread_condattr_setpshared。)
相关问题:Linux 上的 pthread 条件变量,奇怪的行为
我可以很容易地看出 PTHREAD_PROCESS_SHARED 在操作系统级别上实现起来很棘手(例如,MacOS 则不然,除了 rwlocks 之外)。但仅仅从阅读标准来看,你似乎有一个案例。
为了完整起见,您可能想对sysconf(_SC_THREAD_PROCESS_SHARED)和 *_setpshared() 函数调用的返回值进行断言 - 也许还有另一个“惊喜”在等着您(但我可以从注释中看到您已经检查过 SHARED 是实际支持)。
@JesperE:您可能想参考OpenGroup 的 API 文档而不是 HP 文档。