【问题标题】:Error at attaching shared memory segment附加共享内存段时出错
【发布时间】:2017-03-22 04:17:17
【问题描述】:

我有以下代码,我想通过共享内存段在两个进程之间进行通信。我的问题是我在附加内存段时出错,我不知道为什么。

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "process.h"

int main(int argc, char** argv)
{
    /*- Check the command-line arguments -*/
    if(argc != 2)
    {
        printf("\n--- Wrong input at command-line arguments ---\n\n");
        printf("--- The program terminate --- \n");
        return 1;
    }

    int N = atoi(argv[1]);      // The amount of total threads to be created
    int status;         // for the wait() function
    char* data;         // a string to use for shared memory segment

    /*- Variables for the shared memory segment -*/
    key_t key = 1003;       // for the shmget() key argument
    int shmid;          // to store the returned value from shmget()
    int size = 1024;        // for the shmget() size argument


/* ************************************************************************************/

    pid_t pid = fork(); // create second process

    if(pid < 0)     // if something going wrong
    {
        printf("\n\n---- Error in function fork!----\n");
        exit(1);
    }
    else if(pid == 0)   // the child process (P) 
    {
        // create the shared memory segment for the P process
        shmid = CreateShmSegment(key, size, IPC_CREAT);

        if(shmid == -1)     // check if creating shared memory return an error
        {
            printf("\n---Error at creating the memory segment! ---\n");
            exit(1);
        }

        // attach the shared memory segment
        data = AttachShmSegment(shmid);

        if(data == (char*)-1)   // check if attached the shared memory return an error
        {
            printf("\n---Error at attaching the memory segment! ---\n");
            exit(1);
        }   

        char* str = data;
        sprintf(str, "testing");

//      ChildProcess();
        printf("\n** Child process! ** \n");
        printf("N = %d\n", N);
        printf("write: %s\n",str);

        // detach the shared memory segment
        if(shmdt(data) == -1)       //check for error
        {
            printf("\n---Error at detaching memory segment! ---\n");
            exit(1);
        }
    }
    else            // the parent process (C)
    {   
        // create the shared memory segment for the C process
        shmid = CreateShmSegment(key, size, IPC_CREAT);

        if(shmid == -1)     // check if creating shared memory return an error
        {
            printf("\n---Error at creating the memory segment! ---\n");
            exit(1);
        }

        // attach the shared memory segment
        data = AttachShmSegment(shmid);
        if(data == (char*)-1)   // check if attached the shared memory return an error
        {
            printf("\n---Error at attaching the memory segment! ---\n");
            exit(1);
        }   

//      ParentProcess();
        wait(&status);
        printf("\n** Parent process! **\n");
        printf("N = %d\n",N);   
        printf("read from segment: %s\n", data);

        // detach the shared memory segment
        if(shmdt(data) == -1)       //check for error
        {
            printf("\n---Error at detaching memory segment! ---\n");
            exit(1);
        }

        // deallocate the shared memory segment
        if(DeallocateShmSegment(shmid) == -1)   //check for error
        {
            printf("\n---Error at destroy memory segment! ---\n");
            exit(1);
        }
    }

    return 0;
}

我引用和另外两个文件进行编译。

进程.h:

#ifndef __Processes_H_
#define __Processes_H_
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

void    ChildProcess();
void    ParentProcess();
int CreateShmSegment(key_t, size_t, int);
void*   AttachShmSegment(int);
int DetachShmSegment(const void*);
int     DeallocateShmSegment(int);

#endif

和process.c:

#include "process.h"

void ChildProcess()
{

}


/***************************************************************/

void ParentProcess()
{

}

/****************************************************************/

int CreateShmSegment(key_t key, size_t size, int flag)
{
    int id;
    id = shmget(key, size, flag);
    return id;
}

/*****************************************************************/

void* AttachShmSegment(int id)
{
    char* data = NULL;
    data = (char*) shmat(id, NULL, 0);
    return data;
}

/*****************************************************************/

int DetachShmSegment(const void* addr)
{
    return shmdt(addr);
}

/*****************************************************************/

int DeallocateShmSegment(int id)
{
    return shmctl(id, IPC_RMID, NULL);
}

我不知道附加内存出了什么问题。我已经在网上搜索并对 shmat() 的参数进行了一些更改,但我无法解决它。

【问题讨论】:

  • 你说你得到一个错误,但是你得到什么错误?你检查过errno吗?您是否尝试过使用例如strerror 获取可打印的错误字符串?
  • 必须使用System V功能?否则mmap 是管理共享内存的“现代”方式。看看this SO post
  • 一般来说,不要将#include 任何内容放入该文件中未使用的文件中。 IE。在 Process.h 文件中不包含头文件,这些内容未在该文件中使用。只需在实际需要的地方包含那些头文件即可。
  • 一般来说,错误信息应该输出到stderr,而不是stdout,所以在if(argc !=2), The enclosed calls to printf()`之后应该调用fprintf( stderr, ... )
  • 当系统函数返回错误指示时,代码应显示与该错误相关的错误消息。所以这一行:printf("\n---Error at creating the memory segment! ---\n"); 应该类似于:perror( "shared memory create ( shmget() )failed" ); 然后会向 stderr 输出类似于以下的消息:shared memory create (shmget())failed: Permission denied`

标签: c debugging fork shared-memory


【解决方案1】:

这里的问题是您试图在两个进程中获取 shmid,当两个进程调用 CreateShmSegment() 时,它们得到了不同的 shmid,这就是它们失败的原因。

在 fork() 之前调用 CreateShmSegment() 和 AttachShmSegment()。

【讨论】:

  • 在分叉之前创建和附加段是个好主意,但如果不这样做,则不太可能导致错误。共享内存段的父子节点可能获得不同的 ID 是无关紧要的;这些 ID 对每个进程都是本地的。指定的段key用作全局段标识符。
  • @JohnBollinger 我不这么认为,如果您的密钥不同,如何获得共享段。我的意思是,您在 shmget 中传递的密钥对于两个进程应该是相同的。
  • OP确实在两次调用中将相同的密钥传递给shmget()。无论如何,这与您的答案无关,它断言父母和孩子从shmget()/CreateShmSegment()(对于同一个键)接收不同的shmid 值将是一个问题。这种说法是完全错误的。
【解决方案2】:

您在创建段时没有指定任何模式标志。因此,我希望它的创建对任何人(包括其创建者)都没有读写访问权限。这本身并没有错,但是非特权进程在具有该模式时附加该段的所有尝试都应该以EACCES 失败。

大概,您希望在创建段时至少在标志中包含S_IRWXU,或者在修改段的模式以允许对所有者进行读写访问之后使用shmctl()。 (注意执行权限对于这个目的是没有意义的,所以它相当于使用S_IRUSR | S_IWUSR。)例如,

    shmid = CreateShmSegment(key, size, IPC_CREAT | S_IRWXU);

您可能想授予更广泛的访问权限。

还请注意,您先 fork,然后让父进程和子进程创建并附加共享内存段,这很奇怪。附加的共享内存段在fork() 之间继承,因此在分叉之前创建和附加段会更简洁。

【讨论】:

  • 我在 fork 之前已经尝试过。我得到的错误是在附加函数调用之后,它返回'-1'。
  • @aragon,你读过我的全部答案了吗?分叉后shmget()shmat() 的位置是次优的,但不是实际问题。无论如何,当其中一个函数通过返回 -1 指示错误时,获取更多信息的常用机制是直接咨询 errno 或立即调用 perror() 以获取打印到 stderr 的适当错误消息。我敢赌甜甜圈,这样做会暴露出我所描述的访问控制问题。
【解决方案3】:

这种线:

shmid = CreateShmSegment(key, size, IPC_CREAT); 

不正确,应该类似于:

shmid = CreateShmSegment(key, size, IPC_CREAT|0666);

向所有人授予读/写权限(在这种情况下)

一旦创建了共享内存段(没有适当的权限),那么您/用户将不得不销毁共享内存。列出共享内存使用:

ipcs -m 

在结果列表中,

带有dest 的那些不再使用,应该被销毁。

权限列为0的也需要销毁。

您可以通过以下方式销毁共享内存:

ipcrm shm 32768 

其中 32768 是共享内存 ID,取自清单

在代码问题更正和“坏”共享内存被破坏后的代码输出:

** Child process! ** 
N = 2
write: testing

** Parent process! **
N = 2
read from segment: testing

【讨论】:

    猜你喜欢
    • 2012-10-26
    • 1970-01-01
    • 2015-12-01
    • 2011-12-20
    • 1970-01-01
    • 2014-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多