我正在尝试使用shm_open和mmap以及信号量在MacOS X上的两个进程之间共享一块内存。
我遇到的一个问题是,当我运行程序第二次时,当我尝试调用 shm_open()时出现权限错误。
#include "SharedMemory.h"
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include <cassert>
void * run_task(void * context);
const char * mem_name = "/tmp/my_mem2";
const char * sem_name = "/tmp/my_sem2";
int gFileDescr = -1;
void * gSharedMemoryAddr = NULL;
size_t gSharedMemorySize = 0;
sem_t * gSharedMemorySemaphore = NULL;
typedef struct {
completion_proc_t callback;
void * context;
} CallbackAndContext;
void setupSharedMem(size_t mem_size)
{
assert(-1 == gFileDescr);
assert(NULL == gSharedMemoryAddr);
assert(NULL == gSharedMemorySemaphore);
gSharedMemorySize = mem_size;
gFileDescr = shm_open(mem_name, O_RDWR | O_CREAT, 0);
if (gFileDescr <= 0) {
printf("Error, shm_open failed %d %s\n", errno, strerror(errno));
cleanup();
exit(-1);
}
if (ftruncate(gFileDescr, mem_size)) {
printf("ftruncate failed %d %s\n", errno, strerror(errno));
cleanup();
exit(-1);
}
gSharedMemoryAddr = mmap(0, mem_size, PROT_WRITE, MAP_SHARED, gFileDescr, 0);
if (gSharedMemoryAddr == (void *)-1) {
gSharedMemoryAddr = NULL;
printf("Could not map the memory: %d %s\n", errno, strerror(errno));
cleanup();
exit(-1);
}
// open a semaphore to sync memory access.
gSharedMemorySemaphore = sem_open(sem_name, O_CREAT, 0644, 1);
assert(gSharedMemorySemaphore);
int semval;
sem_getvalue(gSharedMemorySemaphore, &semval);
printf("The value of the semaphore is: %d\n", semval);
sem_wait(gSharedMemorySemaphore);
}
void cleanup()
{
if (gSharedMemorySemaphore)
sem_post(gSharedMemorySemaphore);
if (gSharedMemorySemaphore)
sem_close(gSharedMemorySemaphore);
if (gSharedMemoryAddr)
munmap(gSharedMemoryAddr, gSharedMemorySize);
shm_unlink(mem_name);
sem_unlink(sem_name);
}
void askForTask(unsigned char value, completion_proc_t completionProc, void * context)
{
unsigned char * memptr = (unsigned char *) gSharedMemoryAddr;
memptr[0] = value;
CallbackAndContext * candc = (CallbackAndContext *)malloc(sizeof(CallbackAndContext));
candc->callback = completionProc;
candc->context = context;
pthread_t myThread;
pthread_create(&myThread, NULL, run_task, (void *)candc);
}
void * run_task(void * context)
{
CallbackAndContext * candc = (CallbackAndContext *)context;
completion_proc_t comp_proc = NULL;
void * callback_context = NULL;
if (candc) {
comp_proc = candc->callback;
callback_context = candc->context;
free(candc);
}
printf("My Task runner started.\n");
// this will cause the task to start.
if (sem_post(gSharedMemorySemaphore)) {
printf("Error posting to semaphore: %d %s\n", errno, strerror(errno));
cleanup();
exit(-1);
}
// wait for task to be done.
if (sem_wait(gSharedMemorySemaphore)) {
printf("Error acquiring semaphore: %d %s\n", errno, strerror(errno));
cleanup();
exit(-1);
}
printf("Task over\n");
if (comp_proc) {
comp_proc(callback_context);
}
return NULL;
}
在我的main.mm文件中,它看起来像这样:
#define SHARED_MEMORY_BLOCK_SIZE 5000
unsigned char gValue = 0;
extern void * gSharedMemoryAddr;
NSConditionLock * taskLock;
enum {
waiting
,done
};
void MyCompletionProc(void * context)
{
assert(gSharedMemoryAddr);
unsigned char * valPtr = (unsigned char *)gSharedMemoryAddr;
printf("Task Complete Callback: %s\n", gValue == valPtr[1] ? "success" : "fail" );
[taskLock lock];
[taskLock unlockWithCondition:done];
}
int main(int argc, const char * argv[])
{
taskLock = [[NSConditionLock alloc] initWithCondition: waiting];
setupSharedMem(SHARED_MEMORY_BLOCK_SIZE);
NSDate * start_time = [NSDate date];
for (;[[NSDate date] timeIntervalSinceDate:start_time] < 30.0f;) {
askForTask(++gValue, MyCompletionProc, NULL);
[taskLock lockWhenCondition:done];
[taskLock unlockWithCondition:waiting];
sleep(1);
}
cleanup();
return 0;
}
(希望将Objective-C混合在一起不会让人感到困惑。)
我第一次运行该程序似乎可以正常调用askTask一次。 30秒后,它会调用“清理”并退出。
在后续运行中(除非我更改mem_name / sem_name的名称),我收到权限错误。当我重新启动计算机直到下一次时它就消失了。
我做错了什么,如何“重置”或阻止它进入这种状态?
跟进:看来shm_unlink在cleanup()中失败并且权限被拒绝。我不知道为什么。
答案 0 :(得分:4)
解决。
问题是,当调用shm_open时,您需要指定一个“模式”,为用户提供访问共享内存的权限 - 否则在取消链接时会出现权限错误。
gFileDescr = shm_open(mem_name, O_RDWR | O_CREAT, 0);
gFileDescr = shm_open(mem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
我在这里找到答案:https://groups.google.com/forum/#!topic/native-client-reviews/EHHHfK_xPZ4