安全地初始化共享内存

时间:2011-08-21 08:36:39

标签: c macos shared-memory

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

我尝试使用fcntlflock的咨询锁,但都告诉我我传递了无效的文件描述符(我肯定文件描述符无效)。很明显,这是不合适的。

有没有其他选择?或者是否有关于使用我不知道的共享内存锁的详细信息?

编辑: 我尝试使用锁是这样的:

// 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

2 个答案:

答案 0 :(得分:4)

一种常见的技巧是首先使用shm_open来呼叫O_CREAT|O_EXCL。只有一个进程必须进行设置才能成功。其他人则必须像以前一样打开并等待,可能是轮询,设置已完成。

修改:要显示这可以如评论中所讨论的那样发挥作用。

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);  
}

答案 1 :(得分:3)

我能够重现这个问题。然后我在the standard发现了一个悲伤的通知:

  

当文件描述符fildes引用共享内存对象时,   fcntl()的行为应该与普通文件的行为相同,除了   参数cmd的以下值的效果应为   未指定:F_SETFL,F_GETLK,F_SETLK和 F_SETLKW

所以它可能还没有得到支持。对于这样一个简单的设置,我会使用信号量来表示“内存已准备就绪”。

修改

似乎我需要提到可以使用“O_EXCL”创建信号量(因此没有比赛)。