Shared memory allows two unrelated processes to access the same logical memory and is a very efficient way of transferring data between two running processes. If one process writes to the shared memory, the changes immediately become visible to any other process that has access to the same shared memory. The only catch is that by itself shared memory doesn’t provide any synchronization facilities so you usually need to use some other mechanism to synchronize access to the shared memory (e.g. use semaphores). There are no automatic facilities to prevent a second process from starting to read the shared memory before the first process has finished writing to it – it’s the responsibility of the programmer to synchronize access.

Generating A Random Key

Humans aren't very good at picking random values so use a site like this one: www.random.org/integers/

It won't do a 32bit 1 to 2147483647, but it will do 1 to 1000000000

Creating Shared Memory Without Semaphore Interlocking

Header Files Needed

#include <sys/shm.h>		//Used for shared memory
Defining The Shared Memory In Your Header File

//----- SHARED MEMORY -----
struct shared_memory1_struct {
	int some_flag;
	char some_data[1024];
};

void *shared_memory1_pointer = (void *)0;
//VARIABLES:
struct shared_memory1_struct *shared_memory1;
int shared_memory1_id;
Creating The Shared Memory

	//--------------------------------
	//----- CREATE SHARED MEMORY -----
	//--------------------------------
	printf("Creating shared memory...\n");
	shared_memory1_id = shmget((key_t)1234, sizeof(struct shared_memory1_struct), 0666 | IPC_CREAT);		//<<<<< SET THE SHARED MEMORY KEY    (Shared memory key , Size in bytes, Permission flags)
	//	Shared memory key
	//		Unique non zero integer (usually 32 bit).  Needs to avoid clashing with another other processes shared memory (you just have to pick a random value and hope - ftok() can help with this but it still doesn't guarantee to avoid colision)
	//	Permission flags
	//		Operation permissions 	Octal value
	//		Read by user 			00400
	//		Write by user 			00200
	//		Read by group 			00040
	//		Write by group 			00020
	//		Read by others 			00004
	//		Write by others			00002
	//		Examples:
	//			0666 Everyone can read and write

	if (shared_memory1_id == -1)
	{
		fprintf(stderr, "Shared memory shmget() failed\n");
		exit(EXIT_FAILURE);
	}

	//Make the shared memory accessible to the program
	shared_memory1_pointer = shmat(shared_memory1_id, (void *)0, 0);
	if (shared_memory1_pointer == (void *)-1)
	{
		fprintf(stderr, "Shared memory shmat() failed\n");
		exit(EXIT_FAILURE);
	}
	printf("Shared memory attached at %X\n", (int)shared_memory1_pointer);

	//Assign the shared_memory segment
	shared_memory1 = (struct shared_memory1_struct *)shared_memory1_pointer;
Reading And Writing The Shared Memory

	//----- WRITE TO SHARED MEMORY -----
	shared_memory1->some_data[0] = 10;
	shared_memory1->some_flag = 1;


	//----- READ FROM SHARED MEMORY -----
	if (shared_memory1->some_flag == 1)
	{
		char our_copy = shared_memory1->some_data[0];
	}
Deleting The Shared Memory

	//--------------------------------
	//----- DETACH SHARED MEMORY -----
	//--------------------------------
	//Detach and delete
	if (shmdt(shared_memory1_pointer) == -1)
	{
		fprintf(stderr, "shmdt failed\n");
		//exit(EXIT_FAILURE);
	}
	if (shmctl(shared_memory1_id, IPC_RMID, 0) == -1)
	{
		fprintf(stderr, "shmctl(IPC_RMID) failed\n");
		//exit(EXIT_FAILURE);
	}

 

Creating Shared Memory WITH Semaphore Interlocking

The following code works most of the time but there is a problem – in the project we used it on sometimes after power up of the RPi and our application auto running any php call to sem_get() would result in a false return value.  We couldn't find the issue but suspect it may be something to do with the c code rather than the php code (just a hunch).  For our project the semphore wasn't critical so we ended up leaving the semaphore calls in but removing the checks to see if they had worked on the basis that if it worked great but if not the page still got the values it needed as the shared memory itself was working fine. If you use this code and find what the issue could have been please let us know in the comments below!
Header Files Needed

#include <sys/shm.h>		//Used for shared memory
Defining The Shared Memory In Your Header File


//----- SEMAPHORE -----
//On linux systems this union is probably already defined in the included sys/sem.h, but if not use this default basic definition:
union semun {
	int val;
	struct semid_ds *buf;
	unsigned short *array;
};

//FUNCTIONS:
static int semaphore1_get_access(void);
static int semaphore1_release_access(void);
//VARIABLES:
static int semaphore1_id;

//----- SHARED MEMORY -----
struct shared_memory1_struct {
	int some_flag;
	char some_data[1024];
};

void *shared_memory1_pointer = (void *)0;
//VARIABLES:
struct shared_memory1_struct *shared_memory1;
int shared_memory1_id;
The Semaphore Functions


//***********************************************************
//***********************************************************
//********** WAIT IF NECESSARY THEN LOCK SEMAPHORE **********
//***********************************************************
//***********************************************************
//Wait if necessary and then change the semaphore by –1. This is the "wait" operation
static int semaphore1_get_access(void)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1; /* P() */
	sem_b.sem_flg = SEM_UNDO;
	if (semop(semaphore1_id, &sem_b, 1) == -1)		//Wait until free
	{
		fprintf(stderr, "semaphore1_get_access failed\n");
		return(0);
	}
	return(1);
}

//***************************************
//***************************************
//********** RELEASE SEMAPHORE **********
//***************************************
//***************************************
//Setting the semaphore back to available.  This is the "release" operation.

static int semaphore1_release_access(void)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1; /* V() */
	sem_b.sem_flg = SEM_UNDO;
	if (semop(semaphore1_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "semaphore1_release_access failed\n");
		return(0);
	}
	return(1);
}
Creating The Shared Memory


	//-----------------------------------------------
	//----- CREATE SHARED MEMORY WITH SEMAPHORE -----
	//-----------------------------------------------
	printf("Creating shared memory with semaphore...\n");
	semaphore1_id = semget((key_t)12345, 1, 0666 | IPC_CREAT);		//<<<<< SET THE SEMPAHORE KEY (Must be unique and NOT the same as used on whatever other application is using the shared memory)   (Semaphore key, number of semaphores required, flags)
	//	Semaphore key
	//		Unique non zero integer (usually 32 bit).  Needs to avoid clashing with another other processes semaphores (you just have to pick a random value and hope - ftok() can help with this but it still doesn't guarantee to avoid colision)

	//Initialize the semaphore using the SETVAL command in a semctl call (required before it can be used)
	union semun sem_union_init;
	sem_union_init.val = 1;
	if (semctl(semaphore1_id, 0, SETVAL, sem_union_init) == -1)
	{
		fprintf(stderr, "Creating semaphore failed to initialize\n");
		exit(EXIT_FAILURE);
	}
	
	shared_memory1_id = shmget((key_t)1234, sizeof(struct shared_memory1_struct), 0666 | IPC_CREAT);		//<<<<< SET THE SHARED MEMORY KEY    (Shared memory key , Size in bytes, Permission flags)
	//	Shared memory key
	//		Unique non zero integer (usually 32 bit).  Needs to avoid clashing with another other processes shared memory (you just have to pick a random value and hope - ftok() can help with this but it still doesn't guarantee to avoid colision)
	//	Permission flags
	//		Operation permissions 	Octal value
	//		Read by user 			00400
	//		Write by user 			00200
	//		Read by group 			00040
	//		Write by group 			00020
	//		Read by others 			00004
	//		Write by others			00002
	//		Examples:
	//			0666 Everyone can read and write

	if (shared_memory1_id == -1)
	{
		fprintf(stderr, "Shared memory shmget() failed\n");
		exit(EXIT_FAILURE);
	}

	//Make the shared memory accessible to the program
	shared_memory1_pointer = shmat(shared_memory1_id, (void *)0, 0);
	if (shared_memory1_pointer == (void *)-1)
	{
		fprintf(stderr, "Shared memory shmat() failed\n");
		exit(EXIT_FAILURE);
	}
	printf("Shared memory attached at %X\n", (int)shared_memory1_pointer);

	//Assign the shared_memory segment
	shared_memory1 = (struct shared_memory1_struct *)shared_memory1_pointer;
Reading And Writing The Shared Memory


	//----- SEMAPHORE GET ACCESS -----
	if (!semaphore1_get_access())
		exit(EXIT_FAILURE);

	//----- READ / WRITE FROM SHARED MEMORY -----
	if (shared_memory1->some_flag == 1)
	{
		shared_memory1->some_data[0] = 10;
		shared_memory1->some_flag = 0;
	}

	//----- SEMAPHORE RELEASE ACCESS -----
	if (!semaphore1_release_access())
		exit(EXIT_FAILURE);

Deleting The Shared Memory

	//--------------------------------
	//----- DETACH SHARED MEMORY -----
	//--------------------------------
	//Detach and delete
	if (shmdt(shared_memory1_pointer) == -1)
	{
		fprintf(stderr, "shmdt failed\n");
		//exit(EXIT_FAILURE);
	}
	if (shmctl(shared_memory1_id, IPC_RMID, 0) == -1)
	{
		fprintf(stderr, "shmctl(IPC_RMID) failed\n");
		//exit(EXIT_FAILURE);
	}
	//Delete the Semaphore
	//It's important not to unintentionally leave semaphores existing after program execution. It also may cause problems next time you run the program.
	union semun sem_union_delete;
	if (semctl(semaphore1_id, 0, IPC_RMID, sem_union_delete) == -1)
		fprintf(stderr, "Failed to delete semaphore\n");

Debugging

Command line list shared memory:

ipcs -m

Command line list semaphores:

ipcs -s

 

Shared Memory Between A C Application And PHP Web Server

See here.

 

USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.

Comments

  1. Randy Miller

    8 years ago

    I came up with this to read an existing shared memory.


    #define SM_KEY 1234

    shared_memory1_id = shmget((key_t)SM_KEY, sizeof(struct shared_memory1_struct), 0666 | IPC_EXCL); //<<<<< SET THE SHARED MEMORY KEY IPC_EXCL Fail if not exist else returns shmid if (shared_memory1_id != -1) { // returns ID if exists printf("connect to shared memory (shmid: %d)n", shared_memory1_id); //shared_memory1_id = shmget((key_t)SM_KEY, sizeof(struct shared_memory1_struct), 0666 | IPC_CREAT); //<<<<< SET THE SHARED MEMORY KEY (Shared memory key , Size in bytes, Permission flags) } else { printf("Shared memory SM_KEY(0x%08X) does not exist.n", SM_KEY); exit(0); }
    Looks like hell here, I hope it pastes OK.
    basically in the shmget() call IPC_EXCL returns the shmid if it exists, else returns FAIL.

    Use the command "ipcs" to see all of the system shared memory. You can also be sure that your KEY is not already in use.

    Hope this helps.

  2. Moi Moi

    8 years ago

    Hi,
    Thanks for the code , I’ve made it working easily.
    My goal is to share memory between two process , do you have code to read the memory created by the first process.
    Thks you

Comments

Your email address will not be published. Required fields are marked *