[LINUX] Interprocess communication ~ shared memory ~

Purpose

I have summarized my research on "shared memory" in interprocess communication (IPC) as a memorandum.

The following article was very helpful as a summary of the method of interprocess communication. I also used the code as a reference. Linux interprocess communication (Qiita)

The environment here is as follows. The code is written in C ++. MacOS 10.13.4 gcc 7.3.0

I would appreciate it if you could point out any deficiencies.

[Addition] The explanation below is System V shared memory, and it seems that POSIX shared memory also exists.

Commentary

What is shared memory?

According to [Wikipedia](https://ja.wikipedia.org/wiki/shared memory), "shared memory is an efficient way to exchange data between programs." "One process is in memory and another process. Create an area that can also be accessed from. " Exchanging data using one memory area would be a fairly fast process. However, it seems that you have to be careful about conflicts because multiple processes can access the same memory.

Shared memory operation flow

The important thing is that the shared memory is first created independently of the process. After that, it will be linked with multiple processes.

Shared memory operation details

The following functions are provided in Unix to handle shared memory. shmget() (Man page of SHMGET) shmat() (Man page of SHMOP) shmdt() (Man page of SHMOP) shmctl() (Man page of SHMCTL) Please read each Man page for details.

Here, I will explain only the important parts.

shmget() This function is a function that creates shared memory and issues its identifier. It is also used to obtain the identifier of the shared memory that has already been created. It takes three arguments. ・ * Key * This is the IPC key, which can be obtained using ftok () or ʻIPC_PRIVATE. You can think of it as just a unique value. For more information, see [System V IPC Basics](https://www.ksworks.org/memo/net/sysv-ipc.html) and [Man Page of FTOK](https://linuxjm.osdn.jp/html/LDP_man). -Please read pages / man3 / ftok.3.html) and so on. This key is of type key_t, but you need <sys / types.h>` to use it.

・ * Memory size * This must be a multiple of PAGE_SIZE. If that doesn't happen, it seems that they will fix it by increasing it a little.

・ * Flag * You can specify options for creating shared memory and the permissions for the created memory. See Man Page for details. It seems that you can use flags to set permissions (the one used in chmod) other than those listed here.

If you want to get the ID of the created shared memory, you can specify only the key and set the others to 0.

shmat() This function attaches the created shared memory to the process address space. It takes three arguments. ・ * Shared memory ID * This is the value created and returned by shmget ().

・ * Memory address * The address to which you want to attach the shared memory. It seems that if you set this to 0, it will be selected arbitrarily.

・ * Flag * It is for specifying options. Please read Man Page for details.

shmdt() This function separates shared memory from the process's address space. It seems that only one argument is required and the address returned by shmat () is sufficient. It's very easy.

shmctl() This function is used to give various controls over shared memory. Since there are various functions, I would like to leave the details to Man Page. It takes three arguments. ・ * Shared memory ID * The ID of the shared memory you want to control. It's the one issued by shmget ().

·command This is the content of the control you want to perform on the shared memory. In this article, we will use ʻIPC_RMID` to free memory.

· * Pointer to shmid_ds structure * This is a structure for storing the information you want to add to the shared memory. Required when using commands such as ʻIPC_STAT and ʻIPC_SET. Since it is not necessary this time, leave it as NULL (or 0).

Actually use

I'm sure it's okay if I explain this much. Since I explained it with much effort, I will try to make something that actually works. shm_a.cpp manages the shared memory and writes any string to it. shm_b.cpp reads and displays the written content.

Let's run the two in the same directory from different terminals. You can see that the content written in shm_a is also reflected in shm_b.

shm_a.cpp


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
using namespace std;


int main(){
    //Create an empty file
    FILE *fp;
    const string file_path = "./key.dat";
    fp = fopen(file_path.c_str(), "w");
    fclose(fp);

    //Obtaining an IPC key
    const int id = 50;
    const key_t key = ftok(file_path.c_str(), id);
    if(key == -1){
        cerr << "Failed to acquire key" << endl; 
        return EXIT_FAILURE;  
    }

    //Get shared memory ID
    const int size = 0x6400;
    const int seg_id = shmget(key, size, 
                              IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
    if(seg_id == -1){
        cerr << "Failed to acquire segment" << endl;
        return EXIT_FAILURE;
    }

    //Attach shared memory to a process
    char* const shared_memory = reinterpret_cast<char*>(shmat(seg_id, 0, 0));

    //Write to shared memory
    string s;
    int flag = 0;
    cout << "if you want to close, please type 'q'" << endl;
    while(flag == 0){
        cout << "word: ";
        cin >> s;
        if(s == "q") flag = 1;
        else sprintf(shared_memory, s.c_str());
    }

    //Detach shared memory from the process
    shmdt(shared_memory);

    //Free shared memory
    shmctl(seg_id, IPC_RMID, NULL);    

    return 0;
}

shm_b.cpp


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
using namespace std;


int main(){
    //Get the ID of the created shared memory
	const string file_path = "./key.dat";
    const int id = 50;

    const key_t key = ftok(file_path.c_str(), id);

    const int seg_id = shmget(key, 0, 0);
    if(seg_id == -1){
        cerr << "Failed to acquire segment" << endl;
        return EXIT_FAILURE;
    }

    //Attach shared memory to a process
    char* const shared_memory = reinterpret_cast<char*>(shmat(seg_id, 0, 0));

    //Read characters in shared memory
    int flag = 0;
    char c;
    cout << "If you want to close, please type 'q'" << endl;
    cout << "If you want to read the shared memory, push enter button." << endl;
    while(flag == 0){
        cin.get(c);
        if(c == 'q') flag = 1;
        else printf("%s\n", shared_memory);
    }

    //Detach shared memory from the process
    shmdt(shared_memory);

    return 0;
}

When in trouble

There is ʻipcs as a command to manage interprocess communication. This will give you information about the shared memory that exists. So you can check the existence of shared memory by running ʻipcs in another terminal while running shm_a.cpp. Also, if the shared memory is not released properly by forcibly terminating this program, you can delete it using ʻipcrm`. Please read the following site for how to use it. ipcs command-IBM ipcrm --remove interprocess communication ID --IBM

reference

Recommended Posts

Interprocess communication ~ shared memory ~
Linux interprocess communication
Types of interprocess communication
Shared memory between processes
Use shared memory with shared libraries
Interprocess communication for embedded DL