1

私はmmapと共有メモリのサンプルプログラムに取り組んでいます。これが私が試していたコードです、

プロセスB

#include<stdio.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<malloc.h>

typedef struct sh_mem_t{
 int offset;
 char *buffer;
}sh_mem;

int main(){
 int fd;
 sh_mem *shm_obj;

 fd = shm_open("/myshm",O_RDWR,0777);
 if(fd == -1){
  perror("fd:ERROR");
  return -1;
 }

 shm_obj = mmap(0,sizeof(sh_mem),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
 if(shm_obj == MAP_FAILED){
  perror("shm_obj:ERROR");
  return -1;
 }

 printf("\n offset : %d \n",shm_obj->offset);
// printf("\n Good work! : %s \n",shm_obj->buffer);

 return 0;
}

プロセスA

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<sys/sem.h>

typedef struct sh_mem_t{
  int offset;
  char *buffer;
}sh_mem;

int main(int argc,char *argv[]){
  int file_size = 0;
  int fd_sh = 0;
  sh_mem *shmptr = NULL;
  int fd = 0;
  char offset[2];
  int no_bytes_read = 0;
  int read_size = 10;
  int count = 0;
  int ret_val = 0;

  /* Variables for semaphore */
  int ret = 0;
  int semid = 0;
  key_t sem_key = 0;
  struct sembuf op[1];

  union semun{
   int val;
   struct semid_ds *buf;
   unsigned short *array;
  };
  union semun arg;

  /* Validate the i/p parameters */
  if(argc < 3){
   perror("argc:Did u forget the I/P file and the count 0?");
   return -1;
  }
  printf("File : %s",argv[1]);

  count = atoi(argv[2]);

  /* Create a semaphore */
  semid = semget(sem_key,1,IPC_CREAT | 0777);
  if(semid == -1){
   perror("semid:");
   return -1;
  }
  arg.val = 1;
  ret = semctl(semid,0,SETVAL,arg);

  /* Open the file to read the contents */
  fd = open(argv[1],O_RDONLY);

  /* Calculate the total size of the file */
  file_size = lseek(fd,0,SEEK_END);
  lseek(fd,0,SEEK_SET);
  printf("\n File Size is : %d \n",file_size);

  /* Create a new memory object */
  fd_sh = shm_open("/myshm",O_RDWR | O_CREAT,0777);

  /* Set the memory object's size */
  if((ftruncate(fd_sh,sizeof(sh_mem))) == -1){
   perror("ftruncate:ERROR");
   return -1;
  }

  /* Map the Memory object */
 shmptr = mmap(0,sizeof(sh_mem),PROT_READ | PROT_WRITE,MAP_SHARED,fd_sh,0);

  /* Allocate the memory for the buffer */
  shmptr->buffer = malloc((sizeof(char)*file_size));

  printf("\nThe Map address is : 0x%08x\n",shmptr);


 /* Copy the contents to the shared memory */
  read(fd,&offset,1);

  if(count == 0){
   shmptr->offset = 0;
  }


  while(shmptr->offset < file_size){

    /* Semaphore section Start */
    op[0].sem_num=0;
    op[0].sem_op=-1;
    op[0].sem_flg=0;

    semop(semid,op,1);
    printf("\n ProcessA Entering! \n");

    printf("\n initial offset value : %d \n",shmptr->offset);

    if(shmptr->offset > 0){
     shmptr->buffer = shmptr->buffer + shmptr->offset;
     ret_val = lseek(fd,shmptr->offset,SEEK_SET);
    }

    no_bytes_read = read(fd,shmptr->buffer,read_size);

    shmptr->offset = (read_size + shmptr->offset);
    printf("\n offset : %d \n",shmptr->offset);
    printf("\n contents : %s \n",shmptr->buffer);

    sleep(10);

    op[0].sem_op = 1;
    semop(semid,op,1);
    printf("\n ProcessA Leaving ! \n");
    /* Semapore section End*/
  }

  /* Detach from the shared memory */
  shmdt(shmptr);

  close(fd);
  close(fd_sh);

  return 0;
}

プロセスAがあり、データを構造値offsetとbufferを含む共有メモリに入れています。プロセスBは共有メモリ(オフセット、バッファ)に格納されているコンテンツにアクセスしたいのですが、オフセットにしかアクセスできませんでした。バッファにアクセスしようとすると、セグメンテーション違反が発生します。セグメンテーション違反が発生するのはなぜですか。共有オブジェクトは共有メモリにマップされるため。

プロセスAは共有メモリに10バイトを入れてスリープ状態になり、次の10バイトを入れ続けます。

4

1 に答える 1

3

バッファにアクセスしようとすると、セグメンテーション違反が発生します。

bufferマップされたメモリの一部として宣言されpointerています。

typedef struct sh_mem_t{
 int offset;
 char *buffer;
}sh_mem;

プロセス間でポインタを転送することは意味がありません。これは、ポインタがスレーブプロセスでは意味を持たないためです。つまり、ポインタが指すデータは引き続きマスタープロセスに存在します。

マスターからスレーブプロセスに転送する実際のデータを含める必要があります。

typedef struct sh_mem_t{
 int offset;
 char buffer[BUFSIZE];
}sh_mem;

問題の更新されたコードでは、それを機能させるために次の変更が必要です。

  • AとBの両方で、共有メモリ構造体の宣言を次のように変更します。
   typedef struct sh_mem_t{
     int offset;
     char buffer[1024];
   }sh_mem;
  • Aで、malloc()forを削除しshmptr->bufferます。また、オフセット(shmptr->buffer = shmptr->buffer + shmptr->offset;)を追加して、バッファーを調整する行を削除します。それでも必要な場合は、別の方法で処理する必要があります。

  • Bで、出力を出力する行のコメントを解除しGood work!ます。

これらの変更により、のAようなプロセスを開始することができました./A data.txt 0。次にプロセスを開始するBと、プロセスによって最後に印刷されたのと同じように、オフセットとバッファの両方のコンテンツが印刷されAます。

いくつかの追加の発言

  • ヘッダーファイルを使用してsh_mem構造体を宣言し、このファイルを両方の.cファイルにインクルードして、宣言がとの間で一貫していることを確認する必要がAありBます。

  • 上記で投稿したソリューションでは、ファイルサイズが1024を超えるとアプリケーションがクラッシュします。バッファサイズを超えないように、それに応じてこれを処理する必要があります。


なぜポインタで動作しないのですか

スレーブプロセスのマスタープロセスから(非共有)メモリにアクセスすることはできません。特に、共有メモリにポインタを渡すだけではアクセスできません(これにより、共有メモリの概念が廃止されます)。マスタープロセスで割り当てたメモリmalloc()は共有メモリセグメントの一部ではないため、スレーブプロセスからはアクセスできません。

さらに、mmap()デフォルトでは、両方のプロセスで同じ仮想アドレスを返すことは保証されていません。したがって、マスターの共有メモリセグメント内の場所を指すポインタを渡しても、特定のパラメータをに渡さない限り、スレーブプロセス内の有用な場所を指すことはありませんmmap()。詳細については、 mmap(2)を参照してください。

于 2013-03-27T08:50:15.380 に答える