সি-তে লিনাক্সের সাথে কীভাবে ভাগ করা মেমরি ব্যবহার করবেন


117

আমার একটি প্রকল্প নিয়ে আমার কিছুটা সমস্যা আছে।

আমি ভাগ করে নেওয়া মেমরি ব্যবহার করে একটি ভাল ডকুমেন্টেড উদাহরণ খুঁজে পেতে চেষ্টা করেছি fork()তবে সফল হয়নি।

মূলত দৃশ্যটি হ'ল ব্যবহারকারী যখন প্রোগ্রামটি শুরু করেন তখন আমার দুটি শেয়ার করা দরকার শেয়ার্ড মেমোরিতে: কারেন্ট_পথ যা একটি চর * এবং একটি ফাইলের নাম যা এটিও *

কমান্ড আর্গুমেন্টের উপর নির্ভর করে একটি নতুন প্রক্রিয়া শুরু হয় fork()এবং সেই প্রক্রিয়াটি ভাগ করা মেমরিতে সঞ্চিত কারেন্ট_পথ ভেরিয়েবলটি পড়া এবং সংশোধন করা দরকার যখন কেবল ফাইল-নাম ভেরিয়েবলটি পঠিত হয়।

উদাহরণস্বরূপ কোড সহ ভাগ করা মেমরির কোনও ভাল টিউটোরিয়াল আছে (যদি সম্ভব হয়) তবে আপনি আমাকে নির্দেশনা দিতে পারেন?


1
আপনি প্রক্রিয়াগুলির পরিবর্তে থ্রেড ব্যবহার বিবেচনা করতে পারেন। তারপরে পুরো মেমরিটি আর কোনও কৌশল না দিয়ে ভাগ করা হয়।
শ্রুতিমধুরতা

নীচের উত্তরগুলিতে সিস্টেম ভি আইপিসি উভয়ই আলোচনা করে, shmget()ইত্যাদি। এবং (ওরফে ) এর mmap()সাথে খাঁটি পদ্ধতির - যদিও পসিক্স দ্বারা সংজ্ঞায়িত করা হয়নি। POSIX এছাড়াও রয়েছে এবং ভাগ করা মেমোরি অবজেক্টগুলি পরিচালনা করার জন্য। [… অবিরত…]MAP_ANONMAP_ANONYMOUSMAP_ANONshm_open()shm_close()
জোনাথন লেফলার

[… ধারাবাহিকতা…] এর একই সুবিধা রয়েছে সিস্টেম ভি ভি আইপিসি শেয়ার করা মেমরির - ভাগ করা মেমরি অবজেক্টটি যে প্রক্রিয়াটি তৈরি করে তার জীবদ্দশায় অতিক্রম করতে পারে (কিছু প্রক্রিয়া সঞ্চালিত হওয়া অবধি shm_unlink()), তবে ব্যবস্থাগুলি mmap()একটি ফাইলের প্রয়োজন এবং MAP_SHAREDঅবিরত থাকতে পারে ডেটা (এবং MAP_ANONঅধ্যবসায় অন্তর্ভুক্ত)। এর স্পেসিফিকেশনের যৌক্তিক বিভাগে একটি সম্পূর্ণ উদাহরণ রয়েছে shm_open()
জোনাথন লেফলার

উত্তর:


164

দুটি উপায় আছে: shmgetএবং mmap। আমি mmapএটি সম্পর্কে কথা বলব , যেহেতু এটি আরও আধুনিক এবং নমনীয়, তবে আপনি যদি পুরানো শৈলীর সরঞ্জামগুলি ব্যবহার করেন তবে আপনি man shmget( বা এই টিউটোরিয়াল ) একবার দেখে নিতে পারেন ।

mmap()ফাংশন অ্যাক্সেস নিয়ন্ত্রণ করুন ও অনুমতি অত্যন্ত স্বনির্ধারিত পরামিতি সঙ্গে মেমরির বাফার বরাদ্দ করতে ব্যবহার করা যেতে পারে, এবং যদি প্রয়োজন হয় তাহলে ফাইল-সিস্টেম স্টোরেজ সঙ্গে তাদের ব্যাক।

নিম্নলিখিত ফাংশনটি একটি ইন-মেমরি বাফার তৈরি করে যা কোনও প্রক্রিয়া তার বাচ্চাদের সাথে ভাগ করে নিতে পারে:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

void* create_shared_memory(size_t size) {
  // Our memory buffer will be readable and writable:
  int protection = PROT_READ | PROT_WRITE;

  // The buffer will be shared (meaning other processes can access it), but
  // anonymous (meaning third-party processes cannot obtain an address for it),
  // so only this process and its children will be able to use it:
  int visibility = MAP_SHARED | MAP_ANONYMOUS;

  // The remaining parameters to `mmap()` are not important for this use case,
  // but the manpage for `mmap` explains their purpose.
  return mmap(NULL, size, protection, visibility, -1, 0);
}

নিম্নলিখিতটি একটি উদাহরণস্বরূপ প্রোগ্রাম যা একটি বাফার বরাদ্দ করতে উপরের সংজ্ঞায়িত ফাংশনটি ব্যবহার করে। অভিভাবক প্রক্রিয়াটি একটি বার্তা, কাঁটাচামচ লিখবে, এবং তারপরে তার সন্তানের বাফারটি সংশোধন করার জন্য অপেক্ষা করবে। উভয় প্রক্রিয়া ভাগ করা মেমরিটি পড়তে এবং লিখতে পারে।

#include <string.h>
#include <unistd.h>

int main() {
  char parent_message[] = "hello";  // parent process will write this message
  char child_message[] = "goodbye"; // child process will then write this one

  void* shmem = create_shared_memory(128);

  memcpy(shmem, parent_message, sizeof(parent_message));

  int pid = fork();

  if (pid == 0) {
    printf("Child read: %s\n", shmem);
    memcpy(shmem, child_message, sizeof(child_message));
    printf("Child wrote: %s\n", shmem);

  } else {
    printf("Parent read: %s\n", shmem);
    sleep(1);
    printf("After 1s, parent read: %s\n", shmem);
  }
}

52
এই কারণেই লিনাক্স অনভিজ্ঞ দেবদের জন্য এতটাই হতাশাব্যঞ্জক। ম্যান পেজটি কীভাবে আসলে এটি ব্যবহার করবেন তা ব্যাখ্যা করে না এবং কোনও নমুনা কোড নেই। :(
bleepzter

47
হাহা আমি আপনার অর্থ কী তা জানি তবে এটি আসলে কারণ আমরা ম্যানপেজগুলি পড়তে অভ্যস্ত নই। আমি যখন সেগুলি পড়তে শিখেছি এবং তাদের অভ্যস্ত হয়েছি, তখন তারা নির্দিষ্ট বিক্ষোভের সাথে লস টিউটোরিয়ালগুলির চেয়ে আরও বেশি দরকারী হয়ে উঠেছে। আমার মনে আছে আমি আমার অপারেটিং সিস্টেমের কোর্সে পরীক্ষার সময় রেফারেন্সের জন্য ম্যানপেইজ ব্যতীত আর কিছু ব্যবহার করেছি।
slezica

18
shmgetসত্যিই পুরানো fashionতিহ্যবাহী, এবং কেউ কেউ বলেন, হ'ল শেয়ার্ড মেমোরি করার উপায় ... ব্যবহার করা ভাল mmapএবং shm_open, সহজ ফাইল বা সহজভাবে MAP_ANONYMOUS
আর .. গিটহাব বন্ধ করুন আইসিসি

4
@ মার্ক @ আর আপনি ছেলেরা ঠিক বলেছেন, আমি ভবিষ্যতের রেফারেন্সের উত্তরে এটি উল্লেখ করব।
slezica

4
ঠিক আছে, এই উত্তরটি কোনও কারণে জনপ্রিয় হয়েছিল, তাই আমি এটিকে পড়ার পক্ষে মূল্যবান করার সিদ্ধান্ত নিয়েছি। এটি কেবল 4 বছর সময় নিয়েছিল
slezica ২

26

ভাগ করা মেমরির উদাহরণ এখানে:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHM_SIZE 1024  /* make it a 1K shared memory segment */

int main(int argc, char *argv[])
{
    key_t key;
    int shmid;
    char *data;
    int mode;

    if (argc > 2) {
        fprintf(stderr, "usage: shmdemo [data_to_write]\n");
        exit(1);
    }

    /* make the key: */
    if ((key = ftok("hello.txt", 'R')) == -1) /*Here the file must exist */ 
{
        perror("ftok");
        exit(1);
    }

    /*  create the segment: */
    if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
        perror("shmget");
        exit(1);
    }

    /* attach to the segment to get a pointer to it: */
    data = shmat(shmid, NULL, 0);
    if (data == (char *)(-1)) {
        perror("shmat");
        exit(1);
    }

    /* read or modify the segment, based on the command line: */
    if (argc == 2) {
        printf("writing to segment: \"%s\"\n", argv[1]);
        strncpy(data, argv[1], SHM_SIZE);
    } else
        printf("segment contains: \"%s\"\n", data);

    /* detach from the segment: */
    if (shmdt(data) == -1) {
        perror("shmdt");
        exit(1);
    }

    return 0;
}

পদক্ষেপ:

  1. কোনও পাথের নাম এবং একটি প্রকল্প সনাক্তকারীকে একটি সিস্টেম ভি আইপিসি কীতে রূপান্তর করতে ftok ব্যবহার করুন

  2. শেমজেট ব্যবহার করুন যা একটি ভাগ করা মেমরি বিভাগকে বরাদ্দ করে

  3. কলিং প্রসেসের ঠিকানা স্পেসে শ্মিডের দ্বারা চিহ্নিত ভাগ করা মেমরি বিভাগটি সংযুক্ত করতে shmat ব্যবহার করুন

  4. স্মৃতি অঞ্চলে অপারেশন করুন

  5. Shmdt ব্যবহার করে বিচ্ছিন্ন করুন


6
আপনি কেন নুল ব্যবহারের পরিবর্তে 0 টি শূন্যের মধ্যে ফেলছেন?
ক্লিমেট পাউউ 15 '45

তবে এই কোডটি ভাগ করে নেওয়া মেমরি মোছার বিষয়টি পরিচালনা করে না। প্রোগ্রামটি প্রস্থান করার পরে, এটিকে আইপিসিআরএম
মি

12

এগুলি ভাগ করে নেওয়া মেমরির জন্য অন্তর্ভুক্ত

#include<sys/ipc.h>
#include<sys/shm.h>

int shmid;
int shmkey = 12222;//u can choose it as your choice

int main()
{
  //now your main starting
  shmid = shmget(shmkey,1024,IPC_CREAT);
  // 1024 = your preferred size for share memory
  // IPC_CREAT  its a flag to create shared memory

  //now attach a memory to this share memory
  char *shmpointer = shmat(shmid,NULL);

  //do your work with the shared memory 
  //read -write will be done with the *shmppointer
  //after your work is done deattach the pointer

  shmdt(&shmpointer, NULL);

8

এই কোড নমুনাটি ব্যবহার করে দেখুন, আমি এটি পরীক্ষা করেছি, উত্স: http://www.makelinux.net/alp/035

#include <stdio.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 

int main () 
{
  int segment_id; 
  char* shared_memory; 
  struct shmid_ds shmbuffer; 
  int segment_size; 
  const int shared_segment_size = 0x6400; 

  /* Allocate a shared memory segment.  */ 
  segment_id = shmget (IPC_PRIVATE, shared_segment_size, 
                 IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); 
  /* Attach the shared memory segment.  */ 
  shared_memory = (char*) shmat (segment_id, 0, 0); 
  printf ("shared memory attached at address %p\n", shared_memory); 
  /* Determine the segment's size. */ 
  shmctl (segment_id, IPC_STAT, &shmbuffer); 
  segment_size  =               shmbuffer.shm_segsz; 
  printf ("segment size: %d\n", segment_size); 
  /* Write a string to the shared memory segment.  */ 
  sprintf (shared_memory, "Hello, world."); 
  /* Detach the shared memory segment.  */ 
  shmdt (shared_memory); 

  /* Reattach the shared memory segment, at a different address.  */ 
  shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0); 
  printf ("shared memory reattached at address %p\n", shared_memory); 
  /* Print out the string from shared memory.  */ 
  printf ("%s\n", shared_memory); 
  /* Detach the shared memory segment.  */ 
  shmdt (shared_memory); 

  /* Deallocate the shared memory segment.  */ 
  shmctl (segment_id, IPC_RMID, 0); 

  return 0; 
} 

2
এটি একটি ভাল কোড ছাড়া আমি মনে করি না এটি ক্লায়েন্টের দ্বারা ভাগ করে নেওয়া মেমরির বিভাগটি কীভাবে অ্যাক্সেস করতে পারে তা দেখায় (ব্যবহার করে shmgetএবং shmatএকটি পৃথক প্রক্রিয়া থেকে), যা ভাগ করা মেমরির পুরো বিন্দুর মতো ... = (
aletale-cohomology

7

এখানে একটি এমএমএপ উদাহরণ রয়েছে:

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/*
 * pvtmMmapAlloc - creates a memory mapped file area.  
 * The return value is a page-aligned memory value, or NULL if there is a failure.
 * Here's the list of arguments:
 * @mmapFileName - the name of the memory mapped file
 * @size - the size of the memory mapped file (should be a multiple of the system page for best performance)
 * @create - determines whether or not the area should be created.
 */
void* pvtmMmapAlloc (char * mmapFileName, size_t size, char create)  
{      
  void * retv = NULL;                                                                                              
  if (create)                                                                                         
  {                                                                                                   
    mode_t origMask = umask(0);                                                                       
    int mmapFd = open(mmapFileName, O_CREAT|O_RDWR, 00666);                                           
    umask(origMask);                                                                                  
    if (mmapFd < 0)                                                                                   
    {                                                                                                 
      perror("open mmapFd failed");                                                                   
      return NULL;                                                                                    
    }                                                                                                 
    if ((ftruncate(mmapFd, size) == 0))               
    {                                                                                                 
      int result = lseek(mmapFd, size - 1, SEEK_SET);               
      if (result == -1)                                                                               
      {                                                                                               
        perror("lseek mmapFd failed");                                                                
        close(mmapFd);                                                                                
        return NULL;                                                                                  
      }                                                                                               

      /* Something needs to be written at the end of the file to                                      
       * have the file actually have the new size.                                                    
       * Just writing an empty string at the current file position will do.                           
       * Note:                                                                                        
       *  - The current position in the file is at the end of the stretched                           
       *    file due to the call to lseek().  
              *  - The current position in the file is at the end of the stretched                    
       *    file due to the call to lseek().                                                          
       *  - An empty string is actually a single '\0' character, so a zero-byte                       
       *    will be written at the last byte of the file.                                             
       */                                                                                             
      result = write(mmapFd, "", 1);                                                                  
      if (result != 1)                                                                                
      {                                                                                               
        perror("write mmapFd failed");                                                                
        close(mmapFd);                                                                                
        return NULL;                                                                                  
      }                                                                                               
      retv  =  mmap(NULL, size,   
                  PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);                                     

      if (retv == MAP_FAILED || retv == NULL)                                                         
      {                                                                                               
        perror("mmap");                                                                               
        close(mmapFd);                                                                                
        return NULL;                                                                                  
      }                                                                                               
    }                                                                                                 
  }                                                                                                   
  else                                                                                                
  {                                                                                                   
    int mmapFd = open(mmapFileName, O_RDWR, 00666);                                                   
    if (mmapFd < 0)                                                                                   
    {                                                                                                 
      return NULL;                                                                                    
    }                                                                                                 
    int result = lseek(mmapFd, 0, SEEK_END);                                                          
    if (result == -1)                                                                                 
    {                                                                                                 
      perror("lseek mmapFd failed");                  
      close(mmapFd);                                                                                  
      return NULL;                                                                                    
    }                                                                                                 
    if (result == 0)                                                                                  
    {                                                                                                 
      perror("The file has 0 bytes");                           
      close(mmapFd);                                                                                  
      return NULL;                                                                                    
    }                                                                                              
    retv  =  mmap(NULL, size,     
                PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);                                       

    if (retv == MAP_FAILED || retv == NULL)                                                           
    {                                                                                                 
      perror("mmap");                                                                                 
      close(mmapFd);                                                                                  
      return NULL;                                                                                    
    }                                                                                                 

    close(mmapFd);                                                                                    

  }                                                                                                   
  return retv;                                                                                        
}                                                                                                     

openI / O ওভারহেড ফাইল যুক্ত করে। shm_openপরিবর্তে ব্যবহার করুন।
ওসভেইন

1
@ স্পুকবাস্টার, shm_open এর কয়েকটি বাস্তবায়নে ওপেন () কভারের নীচে ডাকা হয়, সুতরাং আপনার মূল্যায়নের সাথে আমার একমত হতে হবে না; এখানে একটি উদাহরণ রয়েছে: কোড. woboq.org/userspace/glibc/sysdeps/posix/shm_open.c.html
লিও

কিছু shm_open () বাস্তবায়ন হুডের অধীনে ওপেন () ব্যবহার করে, shm_open () দ্বারা উত্পাদিত ফাইল বর্ণনাকারীদের জন্য পসিক্সের কম প্রয়োজনীয়তা রয়েছে। উদাহরণস্বরূপ, বাস্তবায়নগুলি shm_open () ফাইল বর্ণনাকারীদের জন্য পড়া () এবং লেখার জন্য () লেখার মতো I / O ফাংশন সমর্থন করার প্রয়োজন হয় না, shm_open () জন্য উন্মুক্ত () জন্য অপ্টিমাইজেশন তৈরি করার জন্য নির্দিষ্ট কিছু প্রয়োগের অনুমতি দেয়। আপনি এটির যা করতে যাচ্ছেন তা যদি এমএমএপ () হয় তবে আপনার shm_open () ব্যবহার করা উচিত।
osvein

Shm_open () ব্যাক করতে tmpfs ব্যবহার করে বেশিরভাগ লিনাক্স-গ্লিবসি সেটআপগুলি এই জাতীয় একটি অপ্টিমাইজেশন তৈরি করে। যদিও একই টিএমপিএফগুলি সাধারণত ওপেন () এর মাধ্যমে অ্যাক্সেস করা যায় তবে এর পথটি জানার কোনও পোর্টেবল উপায় নেই। shm_open () আসুন আপনি সেই অপ্টিমাইজেশনটি একটি বহনযোগ্য পদ্ধতিতে ব্যবহার করুন। পজিক্স shm_open () কে ওপেন () এর চেয়ে আরও ভাল পারফরম্যান্সের সম্ভাবনা দেয়। সমস্ত বাস্তবায়নই সেই সম্ভাবনাকে কাজে লাগাচ্ছে না, তবে এটি ওপেন () এর চেয়ে আরও খারাপ সম্পাদন করবে না। তবে আমি একমত যে আমার দাবি যে ওপেন () সর্বদা ওভারহেড যুক্ত করে তা খুব বিস্তৃত।
osvein
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.