2017-04-25 79 views
0

我在我的“main”函数中拥有这段代码。在复制到共享内存中的结构时获取“总线错误”

... 
int data_size1 = sizeof(dados); 

int fdDados = shm_open("/dados", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 
if (fdDados<0){ 
    perror("shm_open failed"); 
    exit(1); 
} 

dados* shared_data_dados=(dados*) mmap(NULL, data_size1, PROT_READ|PROT_WRITE, MAP_SHARED, fdDados, 0); 
time_t rawtime; 
struct tm * timeinfo; 
time (&rawtime); 
timeinfo = localtime (&rawtime); 
char auxMsg[91]; 
sprintf(auxMsg, "Pid=%d, time=%s", getpid(), asctime(timeinfo)); 
printf(auxMsg); 
strcpy((shared_data_dados->msg), auxMsg); 
... 

,它包括以下.H:

typedef struct { 
    char msg[101]; 
} dados; 

的问题是,当我做的strcpy的结构,它给了我一个总线错误。我已经尝试将结构更改为char *,并将一个char *放在strcpy的原始部分,但我仍然收到相同的错误。 printf打印正确的“消息”,使其不应该成为问题...

任何帮助是apreciated。

在此先感谢!

+0

仅仅因为printf的工作原理,并不意味着你还没有跑出缓冲区的末端 - print strlen(auxMsg)。尝试将shmopen的文件名改为“./dados”。 shmopen创建一个文件描述符 - 如果你没有访问/,它可能不起作用 – cup

+0

我已经尝试了这两个建议,他们都没有工作。正如所示,strlen的printf打印“40”。 –

回答

2
  1. 需要调用ftruncate(fdDados, SIZE)来定义共享存储器对象的大小(SIZE),如在man 3 shm_open手册页中所述。

    默认情况下,共享内存对象的大小为零字节。由于您的映射不受共享内存对象的支持,因此对映射的所有访问都会导致生成一个SIGBUS信号。

    与内存映射文件时的情况完全相同,然后尝试访问文件末尾的映射。
     

  2. mmap()调用中,第二个参数(映射的长度)应该是页面大小的倍数。

    您可以致电sysconf(_SC_PAGESIZE)获取页面大小。不要依赖魔术常量或预处理器宏。
     

  3. 由于(1)和(2)中,最好是通过舍入共享存储器的需要的页面大小的下一个倍数的量来计算SIZE。例如:

    static size_t full_pages(const size_t size) 
    { 
        size_t page = sysconf(_SC_PAGESIZE); 
        if (size < page) 
         return page; 
        else 
        if (size % page) 
         return size + page - (size % page); 
        else 
         return size; 
    } 
    

    并在代码,

    int  shared_fd, len; 
    size_t shared_size; 
    dados *shared_dados; 
    
    shared_size = full_pages(sizeof *shared_dados); 
    shared_fd = shm_open("/dados", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 
    if (shared_fd == -1) { 
        fprintf(stderr, "Cannot create shared object '/dados': %s.\n", strerror(errno)); 
        exit(EXIT_FAILURE); 
    } 
    
    if (ftruncate(shared_fd, (off_t)shared_size) == -1) { 
        fprintf(stderr, "Cannot resize shared object '/dados': %s.\n", strerror(errno)); 
        exit(EXIT_FAILURE); 
    } 
    
    shared_dados = mmap(NULL, shared_size, PROT_READ | PROT_WRITE, 
            MAP_SHARED, shared_fd, 0); 
    if (shared_dados == MAP_FAILED) { 
        fprintf(stderr, "Cannot map shared object '/dados': %s.\n", strerror(errno)); 
        exit(EXIT_FAILURE); 
    } 
    
    if (close(shared_fd) == -1) { 
        fprintf(stderr, "Error closing shared object '/dados': %s.\n", strerror(errno)); 
        exit(EXIT_FAILURE); 
    } else 
        shared_fd = -1; 
    
    /* TODO: LOCKING! */ 
    
    memset(shared_dados->msg, '\0', sizeof shared_dados->msg); 
    len = snprintf(shared_dados->msg, sizeof shared_dados->msg, "pid=%ld", (long)getpid()); 
    if (len < 0 || len >= (int)sizeof shared_dados->msg) { 
        /* The string we tried to print was too long to 
         fit into the shared_dados->msg field. Oops. */ 
    } 
    

    注意,我假定msg构件在dados结构是字符数组。如果它是一个指向char的指针,它将不起作用。 (它会指向一些随机位置,即使您将其设置为指向此进程中的共享内存对象,它将指向其他进程中的错误地址,因为映射本质上将位于随机地址。 )

    另请注意TODO: LOCKING!评论。为确保其他流程只能看到完整的讯息,您应该使用例如围绕访问msg成员的互斥量。

+0

非常感谢!这正是问题,ftruncate失踪了。 –