在 c 中制作共享数据结构 [英] Making a shared data structure in c

查看:47
本文介绍了在 c 中制作共享数据结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的 C 程序中创建了一个数据结构,如下所示,

I have created a data structure in my C program as follows,

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = (int *)malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  if (a->used == a->size) {
    a->size *= 2;
    a->array = (int *)realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

然后我使用以下方法从外部文本文件向该数据结构添加一些数据,

Then I'm adding some data to that data structure from an external text file using following method,

Array read_ints (const char* file_name)
{
  Array numbers;
  initArray(&numbers,5);

  FILE* file = fopen (file_name, "r");
  int i = 0;
  int count = 0;

  fscanf (file, "%d,", &i);  
  insertArray(&numbers,i);  
  while (!feof (file))
    {  
      //printf ("%d ", i);
      fscanf (file, "%d,", &i);
      insertArray(&numbers,i);      
    }
  fclose (file);
  return numbers;        
}

现在我需要做的是,我需要使数组"数据结构成为共享内存部分,以便我的程序上的子进程和父进程都可以访问该数据结构.我不知道如何使它成为共享内存.我知道 shmget() 系统调用可用于在 UNIX 环境中获取共享内存.但是我看不到如何在这种情况下使用该系统调用.请帮帮我.

Now what I need to do is, I need to make the 'Array' data structure a shared memory portion so that the both child and parent processes on my program could access that data structure. I have no idea on how to make it a shared memory. I'm aware that the shmget() system call can be used to get a shared memory in UNIX environment. But i cannot see how to use that system call on this scenario. Please help me.

推荐答案

主要代码 —shm-master.c

#include "posixver.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include "so-stderr.h"

enum { DEFAULT_SHM_SIZE = 65536 };
enum { DEFAULT_FTOK_ID = 0 };
static const char default_filename[] = "/etc/passwd";

static const char usestr[] = "[-adx][-f file][-s size][-i id]";
static const char optstr[] = "adf:s:x";

int main(int argc, char **argv)
{
    int aflag = 0;
    int xflag = 0;
    int dflag = 0;
    int id = DEFAULT_FTOK_ID;
    size_t size = DEFAULT_SHM_SIZE;
    const char *file = default_filename;
    int opt;

    err_setarg0(argv[0]);
    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'a':
            aflag = 1;
            break;
        case 'd':
            dflag = 1;
            break;
        case 'f':
            file = optarg;
            break;
        case 'i':
            id = atoi(optarg);
            break;
        case 's':
            size = strtoull(optarg, 0, 0);
            if (size == 0)
                err_error("Invalid size (%s) evaluates to zero\n", optarg);
            break;
        case 'x':
            xflag = 1;
            break;
        default:
            err_usage(usestr);
        }
    }

    if (aflag + dflag + xflag > 1)
        err_error("%d of 3 mutually exclusive options -a, -d and -x specified\n", aflag + dflag + xflag);

    printf("ID: %d, File: %s\n", id, file);
    key_t key = ftok(file, id);
    printf("Key: 0x%.8" PRIX64 "\n", (uint64_t)key);
    int shmflg = S_IRUSR | S_IWUSR;
    if (!aflag && !dflag)
        shmflg |= IPC_CREAT;
    if (xflag)
        shmflg |= IPC_EXCL;

    int shmid = shmget(key, size, shmflg);
    if (shmid < 0)
        err_syserr("Failed to get shared memory ID: ");
    printf("ShmID: %d\n", shmid);

    if (dflag)
    {
        struct shmid_ds buf;
        int rc = shmctl(shmid, IPC_RMID, &buf);
        if (rc < 0)
            err_syserr("Failed to delete shared memory: ");
        printf("Shared memory removed\n");
    }
    else
    {
        void *space = shmat(shmid, 0, 0);
        if (space == (void *)-1)
            err_syserr("Failed to attach to shared memory: ");
        printf("Shared memory allocated at 0x%" PRIXPTR "\n", (uintptr_t)space);
        memset(space, '\0', size);
        int rc = shmdt(space);
        if (rc != 0)
            err_syserr("Failed to detach from shared memory: ");
        printf("Detached from shared memory\n");
    }

    return 0;
}

库代码—so-stderr.h

#ifndef SO_STDERR_H_INCLUDED
#define SO_STDERR_H_INCLUDED

extern void err_setarg0(const char *arg0);
extern void err_error(const char *fmt, ...);
extern void err_syserr(const char *fmt, ...);

#endif /* SO_STDERR_H_INCLUDED */

库代码—so-stderr.c

#include "so-stderr.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char *argv0 = "**undefined**";

void err_setarg0(const char *arg0)
{
  argv0 = arg0;
}

void err_error(const char *fmt, ...)
{
  fprintf(stderr, "%s: ", argv0);
  va_list args;
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  exit(EXIT_FAILURE);
}

void err_syserr(const char *fmt, ...)
{
  int errnum = errno;
  fprintf(stderr, "%s: ", argv0);
  va_list args;
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  if (errnum != 0)
    fprintf(stderr, "(%d: %s)", errnum, strerror(errnum));
  putc('\n', stderr);
  exit(EXIT_FAILURE);
}

配置标题 —posixver.h

您可以在许多系统上将更高的版本号调整为 700(对于 POSIX 2008/2013),但在 Mac OS X 上可能不是一个好主意,即使是 10.10.3 Yosemite.

Configuration header — posixver.h

You can adjust the higher version number to 700 (for POSIX 2008/2013) on many systems, but it probably isn't a good idea on Mac OS X, even with 10.10.3 Yosemite.

#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H

#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif

#endif

在所有情况下,真实"代码都包含(一些)注释和其他对正在发生的事情的解释.生产stderr.hstderr.c 比显示的最小版本更复杂,但出于许多目的,显示的内容等同于生产版本.

In all cases, the 'real' code includes (a few) comments and other explanations of what's going on. The production stderr.h and stderr.c are more complex than the minimal version shown, but for many purposes, what's shown is equivalent to the production version.

$ ./shm-master -H
./shm-master: invalid option -- 'H'
Usage: ./shm-master [-adx][-f file][-s size][-i id]
$ ./shm-master -ax
./shm-master: 2 of 3 mutually exclusive options -a, -d and -x specified
$ ./shm-master -dx
./shm-master: 2 of 3 mutually exclusive options -a, -d and -x specified
$ ./shm-master -da
./shm-master: 2 of 3 mutually exclusive options -a, -d and -x specified
$ ./shm-master -dax
./shm-master: 3 of 3 mutually exclusive options -a, -d and -x specified
$ ipcs -m | grep -v '^0x00000000 '

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x620010f7 0          root       660        557920     4
0x63002725 32769      root       666        82164      3

$ ./shm-master -x
ID: 0, File: /etc/passwd
Key: 0x0000009F
ShmID: 44793901
Shared memory allocated at 0x7F29AC43A000
Detached from shared memory
$ ipcs -m | grep -v '^0x00000000 '

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x620010f7 0          root       660        557920     4
0x63002725 32769      root       666        82164      3
0x0000009f 44793901   jleffler   600        65536      0

$ ./shm-master -d
ID: 0, File: /etc/passwd
Key: 0x0000009F
ShmID: 44793901
Shared memory removed
$ ipcs -m
$ grep -v '^0x00000000 '

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x620010f7 0          root       660        557920     4
0x63002725 32769      root       666        82164      3

$ ./shm-master -f /home/jleffler/soq/shm-master -a
./shm-master: Failed to get shared memory ID: (2: No such file or directory)
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
$ ./shm-master -f /home/jleffler/soq/shm-master -d
./shm-master: Failed to get shared memory ID: (2: No such file or directory)
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
$ ./shm-master -f /home/jleffler/soq/shm-master -x
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44826669
Shared memory allocated at 0x7FA1488CA000
Detached from shared memory
$ ./shm-master -f /home/jleffler/soq/shm-master -d
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44826669
Shared memory removed
$ ./shm-master -f /home/jleffler/soq/shm-master -x
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44859437
Shared memory allocated at 0x7F93005EC000
Detached from shared memory
$ shmid=$(./shm-master -f /home/jleffler/soq/shm-master -a sed -n '/ShmID: /s///p')
$ ipcs -m -i $shmid

Shared memory Segment shmid=44859437
uid=199484      gid=5000        cuid=199484     cgid=5000
mode=0600       access_perms=0600
bytes=65536     lpid=31202      cpid=31200      nattch=0
att_time=Fri Apr 17 11:37:06 2015
det_time=Fri Apr 17 11:37:06 2015
change_time=Fri Apr 17 11:37:06 2015

$ ./shm-master -f /home/jleffler/soq/shm-master -d
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44859437
Shared memory removed
$

顺便说一下,ipcs 选项 -i id 是基于 ipcs,并且该选项在例如 Mac OS X (BSD) 上不可用.最接近的等价物类似于 ipcs -m -a |grep "$shmid",这并不完美.grep -v '^0x00000000 ' 操作消除了私有共享内存段(在我进行测试的机器上使用了很多).

Incidentally, the ipcs option -i id is a Linux extension over the POSIX specification for ipcs, and the option is not available on, for example, Mac OS X (BSD). The nearest equivalent would be something like ipcs -m -a | grep "$shmid", which isn't perfect. The grep -v '^0x00000000 ' operations eliminate the private shared memory segments (there were a lot of them in use on the machine I did the testing on).

这篇关于在 c 中制作共享数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆