Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 安全初始化共享内存_C_Macos_Shared Memory - Fatal编程技术网

C 安全初始化共享内存

C 安全初始化共享内存,c,macos,shared-memory,C,Macos,Shared Memory,我有几个进程通过OSX上的POSIX共享内存与每个进程通信。 我的问题是这些进程可能以任何顺序生成,并尝试同时初始化共享内存段 我尝试将建议锁与fcntl和flock一起使用,但都没有告诉我传递了无效的文件描述符(我肯定文件描述符不是无效的)。很明显,这是不可能的 有没有别的办法?或者有没有我不知道的关于使用共享内存锁的细节 编辑: 我使用锁的尝试如下所示: // Some declarations... struct Queue {

我有几个进程通过OSX上的POSIX共享内存与每个进程通信。 我的问题是这些进程可能以任何顺序生成,并尝试同时初始化共享内存段

我尝试将建议锁与
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.第一个进程完成之间有一段时间