C 安全初始化共享内存
我有几个进程通过OSX上的POSIX共享内存与每个进程通信。 我的问题是这些进程可能以任何顺序生成,并尝试同时初始化共享内存段 我尝试将建议锁与C 安全初始化共享内存,c,macos,shared-memory,C,Macos,Shared Memory,我有几个进程通过OSX上的POSIX共享内存与每个进程通信。 我的问题是这些进程可能以任何顺序生成,并尝试同时初始化共享内存段 我尝试将建议锁与fcntl和flock一起使用,但都没有告诉我传递了无效的文件描述符(我肯定文件描述符不是无效的)。很明显,这是不可能的 有没有别的办法?或者有没有我不知道的关于使用共享内存锁的细节 编辑: 我使用锁的尝试如下所示: // Some declarations... struct Queue {
fcntl
和flock
一起使用,但都没有告诉我传递了无效的文件描述符(我肯定文件描述符不是无效的)。很明显,这是不可能的
有没有别的办法?或者有没有我不知道的关于使用共享内存锁的细节
编辑:
我使用锁的尝试如下所示:
// Some declarations...
struct Queue {
int index[ENTRIES_PER_QUEUE];
sem_t lock;
sem_t readWait;
sem_t writeSem;
struct Entry slots[ENTRIES_PER_QUEUE];
};
struct ipc_t {
int fd;
char name[512];
struct Queue* queue;
};
ipc_t ipc_create(const char* name, int owner) {
int isInited = 1;
struct Queue* queue;
struct flock lock = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0
};
ipc_t conn = malloc(sizeof(struct ipc_t));
sprintf(conn->name, "/arqvenger_%s", name);
conn->fd = shm_open(conn->name, O_CREAT | O_RDWR, 0666);
if (conn->fd == -1) {
free(conn);
perror("shm_open failed");
return NULL;
}
if (fcntl(conn->fd, F_SETLKW, &lock) == -1) {
perror("Tanked...");
}
// Do stuff with the lock & release it
我得到的结果是:
Tanked...: Bad file descriptor
一种常见的技术是首先使用
O|u create | O_EXCL
调用shm_open
。这将只在一个必须进行设置的进程中成功。其他人则必须像以前一样打开,等待一点,可能是轮询,以确保安装完成
编辑:以显示如何按照评论中的讨论进行操作
struct head {
unsigned volatile flag;
pthread_mutex_t mut;
};
void * addr = 0;
/* try shm_open with exclusive, and then */
if (/* we create the segment */) {
addr = mmap(something);
struct head* h = addr;
pthread_mutex_init(&h->mut, aSharedAttr);
pthread_mutex_lock(&h->mut);
h->flag = 1;
/* do the rest of the initialization, and then */
pthread_mutex_unlock(&h->mut);
} else {
/* retry shm_open without exclusive, and then */
addr = mmap(something);
struct head* h = addr;
/* initialy flag is guaranteed to be 0 */
/* this will break out of the loop whence the new value is written to flag */
while (!h->flag) sched_yield();
pthread_mutex_lock(&h->mut);
pthread_mutex_unlock(&h->mut);
}
一种常见的技术是首先使用
O|u create | O_EXCL
调用shm_open
。这将只在一个必须进行设置的进程中成功。其他人则必须像以前一样打开,等待一点,可能是轮询,以确保安装完成
编辑:以显示如何按照评论中的讨论进行操作
struct head {
unsigned volatile flag;
pthread_mutex_t mut;
};
void * addr = 0;
/* try shm_open with exclusive, and then */
if (/* we create the segment */) {
addr = mmap(something);
struct head* h = addr;
pthread_mutex_init(&h->mut, aSharedAttr);
pthread_mutex_lock(&h->mut);
h->flag = 1;
/* do the rest of the initialization, and then */
pthread_mutex_unlock(&h->mut);
} else {
/* retry shm_open without exclusive, and then */
addr = mmap(something);
struct head* h = addr;
/* initialy flag is guaranteed to be 0 */
/* this will break out of the loop whence the new value is written to flag */
while (!h->flag) sched_yield();
pthread_mutex_lock(&h->mut);
pthread_mutex_unlock(&h->mut);
}
我已经能够重现这个问题。然后我发现了一个悲伤的通知: 当文件描述符fildes引用共享内存对象时 fcntl()的行为应与常规文件相同,但 参数cmd的以下值的影响应为 未指定:F_SETFL、F_GETLK、F_SETLK和F_SETLKW 所以它可能还没有得到支持。对于这样一个简单的设置,我将使用一个信号量来表示“内存已准备就绪” 编辑
似乎我需要提到,可以使用“O_exc”创建信号量(因此没有种族)。我已经能够重现这个问题。然后我发现了一个悲伤的通知: 当文件描述符fildes引用共享内存对象时 fcntl()的行为应与常规文件相同,但 参数cmd的以下值的影响应为 未指定:F_SETFL、F_GETLK、F_SETLK和F_SETLKW 所以它可能还没有得到支持。对于这样一个简单的设置,我将使用一个信号量来表示“内存已准备就绪” 编辑
似乎我需要提到的是,信号量可以使用“O_EXCL”(因此没有种族)创建。@cnicutar我觉得代码会掩盖眼前的问题,但如果你觉得它会有帮助,它正在进行中。代码看起来不错。我尝试了一个单独的例子,它奏效了。@cnicutar那是在linux上的吗?我忘了提到我正在使用OS X。很明显,回顾过去,这是一个重要的因素。好吧,我有一个免费的BSD,别动:-)@cnicutar我觉得代码会掩盖眼前的问题,但如果你觉得它会有帮助,它就在路上了。我觉得代码看起来不错。我尝试了一个单独的例子,它奏效了。@cnicutar那是在linux上的吗?我忘了提到我正在使用OS X。很明显,回顾起来,这是一个重要的因素。好吧,我有一个FreeBSD,待在原地:-)我考虑过这样做,并放弃了它,因为它要么意味着忙着等待,要么意味着使用usleep,而这对我来说并不合适。但是如果没有其他方法,我想我可以回到这个问题上来。这种睡眠实际上只需要很短的初始时间,一个标志和互斥的初始化,例如,你肯定不需要任何繁忙的等待或睡眠。尝试
shm_open(…O_RDWR | O|u create | O|u EXCL)
。如果失败,这意味着另一个进程已经创建了您的共享内存。现在请尝试shm\u open(…O\u RDWR)
。如果失败了,就没有更多的尝试了。第二次呼叫将不会成功。记录致命错误并退出。我想知道在这个序列中哪里可以引入忙等待的概念。@n.m.从第一个进程成功创建到完成初始化之间有一段时间。例如,您可以在段的开头放置一个pthread\u mutex\u t
。但是,您仍然必须等待另一个进程,直到互斥体被初始化。因此,您需要一个标志来指示互斥已初始化,所有其他进程都必须轮询该标志。对于所有其他锁结构,这是相同的,您必须确保它们已初始化,然后才能使用它们。唯一能做到这一点的过程是创造者,所以有一个很短的差距。@Jens Gustedt:好的,我明白你的意思了。在Linux 2.6及更高版本上,您可以使用POSIX
信号量来实现命名的进程间互斥(如果POSIX
信号量可用,boost::interprocess::named_mutex
就是这样做的)。那你就不用在任何地方等了。如果POSIX
信号量或某些等效机制不可用,则可能忙等待是唯一的选项(同样,这也是boost::interprocess::named_mutex
所做的)。我不确定OSX在这方面的立场。我考虑过这样做,并放弃了它,因为它要么意味着忙着等待,要么意味着使用usleep,而这对我来说并不合适。但是如果没有其他方法,我想我可以回到这个问题上来。这种睡眠实际上只需要很短的初始时间,一个标志和互斥的初始化,例如,你肯定不需要任何繁忙的等待或睡眠。尝试shm_open(…O_RDWR | O|u create | O|u EXCL)
。如果失败,这意味着另一个进程已经创建了您的共享内存。现在请尝试shm\u open(…O\u RDWR)
。如果失败了,就没有更多的尝试了。第二次呼叫将不会成功。记录致命错误并退出。我想知道在这个序列中哪里可以引入忙等待的概念。@n.m.第一个进程完成之间有一段时间