2016-11-03 26 views
5

私は2つの異なるアプリケーションの間でPOSIXモデル内に共有動的配列を持っています。コピーせずにサイズを変更できるようにしたいと思います。残念ながら、私はC言語でPOSIX共有メモリを増減する適切な解決策を見つけることができませんでした。ウェブでは、説明が不十分で悲惨な例が多い多くの文書が見つかりました。私はいくつかの興味深いトピックを見つけることができましたが、それらのすべては、私には不向きである:POSIX共有メモリのサイズを変更します。動作例

  1. "Linux System Programming" - "Mapping Files into Memory" Part: "Resizing a Mapping" - どこSHMのサイズを変更するには、no実施例ではありません。

  2. How do I implement dynamic shared memory resizing? - 説明のみ。例はありません。

  3. mremap function failed to allocate new memory - お気に入りの回答が間違っています。

  4. mremap function failed to allocate new memory

  5. c/linux - ftruncate and POSIX Shared Memory Segments

    Characteristics of mremap function in Linux

  6. Fast resize of a mmap file

  7. - rszshmがすべてではmremap()を使用していません。代わりにメモリをコピーします。最悪の方法。

私はこのドキュメントをよく理解しています。残念ながら、それは正しく動作していません。私が間違っているアドバイスをお願いします。そして私に実例を与えるほど親切にしてください。

ドキュメントでは、mremap()の前にftruncate()を使用する必要があることがわかりましたが、それらを使用するための正しい構文が見つかりませんでした。さらに、mremap()は整列したメモリページで動作します。この場合、共有メモリを適切に増やすにはどうすればよいですか?

/* main.c */ 
#define _GNU_SOURCE 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <errno.h> 

int main(void) 
{ 
    size_t size_of_mem = 1024; 
    int fd = shm_open("/myregion", O_CREAT | O_RDWR, 
         S_IRWXO | S_IRUSR | S_IWUSR); 
    if (fd == -1) 
    { 
     perror("Error in shm_open"); 
     return EXIT_FAILURE; 
    } 

    if (ftruncate(fd, size_of_mem) == -1) 
    { 
     perror("Error in ftruncate"); 
     return EXIT_FAILURE; 
    } 

    void *shm_address = mmap(0, size_of_mem, 
          PROT_READ | PROT_WRITE | PROT_EXEC, 
          MAP_SHARED, fd, 0); 
    if (shm_address == MAP_FAILED) 
    { 
     perror("Error mmapping the file"); 
     return EXIT_FAILURE; 
    } 

    /* Increase shard memory */ 
    for (size_t i=0; i<1024; ++i){ 

     /* Does 8 align memory page? */ 
     size_t new_size_of_mem = 1024+(8*i); 

     if (ftruncate(fd, new_size_of_mem) == -1) 
     { 
      perror("Error in ftruncate"); 
      return EXIT_FAILURE; 
     } 

     /* 
      mremap() works with aligned memory pages. 
      How to properly increase shared memory in this case? 
     */ 
     void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE); 
     if(temp == (void*)-1) 
     { 
      perror("Error on mremap()"); 
      return EXIT_FAILURE; 
     } 

     size_of_mem = new_size_of_mem; 

    } 

    return 0; 
} 

ビルド:

$ gcc -g -O0 -ggdb -pipe -Wall -Wextra -Wpedantic -Wshadow -march=native -std=c11 -o ./main ./main.c -lrt 

ラン:

$ ./main 
Error on mremap(): Bad address 
+0

少なくとも、ページサイズの点でサイズを測定する必要があります。 'getpagesize()'または 'sysconf()'を参照してください。また、プロセス間でメモリを共有するためには、新しいサイズを他のプロセスに伝える方法を見つけなければなりません。 – joop

答えて

2

あなたはtempに割り当てられた新しい割り当てられた/再マップメモリ​​のアドレスを失うされています。

これは、forループの2番目のサイクル以降、すでに移動したメモリを移動していることを意味します。

mremapの戻り値のチェックの後、shm_addressポインタに新しいアドレスを再指定できます。

void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE); 
if(temp == (void*)-1) 
{ 
    perror("Error on mremap()"); 
    return EXIT_FAILURE; 
} 

shm_address = temp; 
+0

ありがとうございます。今それは本当にエラーなく動作します。残りの質問はどうですか? mremap()は、整列したメモリページで動作します。この場合、共有メモリを適切に増やすにはどうすればよいですか? –

+1

これは大きな問題です。いくつかのLinux managemnt guruから良い説明を得るために別の質問を投稿してください。ここで言うことができるのは、呼び出し元によって提供されたlenパラメータがページ境界に揃えられていない場合、マッピングは次のフルページに切り上げられます。最後に有効なバイトとマッピングの終わりの間に、この追加されたメモリ内のバイトはゼロで埋められます。その領域からの読み込みはゼロを返します。 – LPs

+0

もう一度ありがとうございます。非常に便利! –