Posix在父进程和子进程之间共享内存?

时间:2015-08-26 10:23:54

标签: c++ c posix ubuntu-14.04

我正在编写一个程序来解决操作系统概念一书中的练习。这个问题是在子进程上创建一个Collat​​z猜想,并使用Posix共享内存将其打印回父进程。这是我的计划。

int main(int argc, char* argv[])
{
const char* name = "Collatz";
const int SIZE = 4096 * 30;
void *ptr;
int shm_fd;
int num = atoi(argv[1]);
pid_t pid;

shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, SIZE);
ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr < 0) perror("Ptr error");
pid = fork();
if (pid < 0) perror("Fork Failed");
else if (pid == 0) {
    shm_fd = shm_open(name, O_RDWR, 0666);
    ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (ptr < 0) perror("Ptr error");
    while (num != 1) {
        sprintf(ptr, "%d", num);
        ptr++;
        if (num % 2 == 0) num /= 2;
        else num = 3 * num + 1;
    }
    sprintf(ptr, "%d", num);
    ptr++;
} else {
    wait(NULL);
    printf("Parent: %s\n", (char*) ptr);

    //ptr += sizeof(int);
    shm_unlink(name);
}
return 0;
}

但是当我用 gcc 编译它时,我得到分段错误(核心转储)。虽然搜索谷歌,但我不知道它。我使用Ubuntu 14.04。有人可以帮助我。非常感谢,抱歉我的英语不好。

2 个答案:

答案 0 :(得分:2)

我尝试使用以下包含编译您的代码,它对我有用。

./collatz 12 

你有没有想过在执行程序时传递一个整数参数? (例如)

 CREATE TABLE IF NOT EXISTS `configuration_changed` (
`table_name` TEXT(30) NOT NULL,
`column_name` VARCHAR(45) NULL,
`idbox` INT(11) UNSIGNED NOT NULL,
`pk` TEXT NOT NULL,
`old_value` VARCHAR(45) NULL,
`new_value` VARCHAR(45) NULL,
`date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`type` ENUM('NEW','DELETE','CHANGE') NULL,
INDEX `FK_conf_changed_idbox_idx` (`idbox` ASC),
CONSTRAINT `FK_conf_changed_idbox`
FOREIGN KEY (`idbox`)
REFERENCES `box` (`id`)
ON DELETE CASCADE
ON UPDATE RESTRICT)

输出1631518421

答案 1 :(得分:0)

这是我的解决方案,希望对您有所帮助。共享内存通过系统功能mmap(2)加载到进程的后面。

void ∗ mmap (void ∗ addr, size_t len, int prot, int flags, int fd, off_t offset);

参数为:
   •addr-要加载到进程中的地址(通常在这里我们使用0来让内核决定加载位置)
   •加载的内存大小•Prot-访问权限(通常为PROTREAD或PROTWRITE)
   •标志-内存类型(通常为MAPSHARED,以便其他人可以看到该进程所做的更改)
   •fd-内存对象的描述符
   •offset-共享内存对象中的位置,将从中重播该位置。
    成功执行后,结果是指向对象已加载到的进程空间中地址的指针。否则,将返回MAPFAILED值,并将errno设置为适当的值。     请注意,在Linux中,大小必须是页面的倍数:PAGE_SIZE(为此,我使用了getpagesize(2))

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <sys/mman.h>
    #include <sys/sysmacros.h>

    int main(int argc, char *argv[])
    {
        fprintf(stdout, "Starting parent %d\n", getpid());

        int wstatus, shm_fd;
        char shm_name[] = "collatz";
        struct stat sb;
        pid_t pid;
        unsigned int displacement = 0,  offset = 0;
        size_t shm_size = getpagesize() * (argc - 1);

        if(argc < 2)
        {
            fprintf(stderr, "At least one argument must be passed!");
            exit(EXIT_FAILURE);
        }

        int *pid_children = (int*)malloc((argc - 1) * sizeof(int));
        if(pid_children == NULL)
        {
            fprintf(stderr, "Memory not allocated!");
            exit(1);
        }

        /* Create shared memory object */
        shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
        if(shm_fd < 0)
        {
            perror(NULL);
            return errno;
        }

        /* Define size */
        if(ftruncate(shm_fd, shm_size) == -1) {
            perror(NULL);
            shm_unlink(shm_name);
            return errno;
        }

        for(int i = 1; i < argc; i ++)
        {
            int n = atoi(argv[i]), aux = atoi(argv[i]);
            if(n < 0)
            {
                fprintf(stderr, "Only positive numbers!\n");
                i = i + 1;
            }

            pid_children[i - 1] = fork();
            if(pid_children[i - 1] < 0)
                return errno;
            if(pid_children[i - 1] == 0)
            {
                /* Child instructions */
                char *shm_ptr_child = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, (i - 1) * getpagesize());
                if(shm_ptr_child == MAP_FAILED)
                {
                    perror(NULL);
                    shm_unlink(shm_name);
                    return errno;
                }

                int count = 0;
                int *series = (int*)malloc(count * sizeof(int));
                if(series == NULL)
                {
                    fprintf(stderr, "Memory allocation error!");
                    exit(1);
                }

                *(series + count) = n;
                while(n != 1)
                {
                    count = count + 1;
                    series = (int*)realloc(series, (count + 1) * sizeof(int));
                    if(series ==  NULL)
                    {
                        fprintf(stderr, "Memory allocation failure!");
                        free(series);
                        exit(EXIT_FAILURE);
                    }

                    if(n % 2== 0)
                        n = n / 2;
                    else
                        n = 3 * n + 1;

                    *(series + count) = n;
                }
                if(n == 1){
                    offset = sprintf(shm_ptr_child, "%d : ", aux);
                    shm_ptr_child += offset;
                    for(int i = 0; i < count + 1; i++)
                    {
                        offset = sprintf(shm_ptr_child, "%d ", series[i]);
                        shm_ptr_child += offset;
                    }

                    free(series);
                    munmap(shm_ptr_child, getpagesize());

                    fprintf(stdout, "Done Parent: %d, Me: %d \n", getppid(), getpid());
                    exit(EXIT_SUCCESS);
                }
                else
                    exit(EXIT_FAILURE);
            }
            else{
                /* Parent instructions */
                do{
                    pid = waitpid(pid_children[i - 1], &wstatus, WUNTRACED | WCONTINUED);
                    if(pid == -1)
                    {
                        perror("waitpid");
                        return -1;
                    }

                    if(WIFEXITED(wstatus)){
                        fprintf(stdout, "exited, status = %d\n", WEXITSTATUS(wstatus));
                    }else if(WIFSIGNALED(wstatus)) {
                        fprintf(stdout, "killed by the signal: %d\n", WTERMSIG(wstatus));
                    }else if(WIFSTOPPED(wstatus)) {
                        fprintf(stdout, "stopped by the signal %d\n", WSTOPSIG(wstatus));
                    }else if(WIFCONTINUED(wstatus)) {
                        fprintf(stdout, "continued\n");
                    }

                }while(!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));

            }
        }

        for(int i = 0; i < argc - 1; i++)
        {
            char *shm_ptr = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, shm_fd, i * getpagesize());
            fprintf(stdout, "%s\n", shm_ptr);
            munmap(shm_ptr, getpagesize());
        }
        shm_unlink(shm_name);

        printf("\nDone Parent: %d, Children: %d \n", getppid(), getpid());

        return 0;
}