{"id":748,"date":"2013-01-30T14:07:37","date_gmt":"2013-01-30T14:07:37","guid":{"rendered":"https:\/\/raspberry-projects.com\/pi\/?p=748"},"modified":"2018-04-17T13:13:42","modified_gmt":"2018-04-17T13:13:42","slug":"shared-memory","status":"publish","type":"post","link":"https:\/\/raspberry-projects.com\/pi\/programming-in-c\/memory\/shared-memory","title":{"rendered":"Shared Memory"},"content":{"rendered":"<p>\nShared 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.&nbsp;The only catch is that by itself shared memory doesn&rsquo;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 &#8211; it&rsquo;s the responsibility of the programmer to synchronize access.\n<\/p>\n<h4>\nGenerating A Random Key<br \/>\n<\/h4>\n<p>\nHumans aren&#39;t very good at picking random values so use a site like this one: <a href=\"http:\/\/www.random.org\/integers\/\" target=\"_blank\">www.random.org\/integers\/<\/a>\n<\/p>\n<p>\nIt won&#39;t do a 32bit 1 to 2147483647, but it will do 1 to 1000000000\n<\/p>\n<h4>\nCreating Shared Memory Without Semaphore Interlocking<br \/>\n<\/h4>\n<h5>\nHeader Files Needed<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n#include &lt;sys\/shm.h&gt;\t\t\/\/Used for shared memory\r\n<\/code><\/pre>\n<h5>\nDefining&nbsp;The Shared Memory In Your Header File<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\/\/----- SHARED MEMORY -----\r\nstruct shared_memory1_struct {\r\n\tint some_flag;\r\n\tchar some_data[1024];\r\n};\r\n\r\nvoid *shared_memory1_pointer = (void *)0;\r\n\/\/VARIABLES:\r\nstruct shared_memory1_struct *shared_memory1;\r\nint shared_memory1_id;\r\n<\/code><\/pre>\n<h5>\nCreating The Shared Memory<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\t\/\/--------------------------------\r\n\t\/\/----- CREATE SHARED MEMORY -----\r\n\t\/\/--------------------------------\r\n\tprintf(&quot;Creating shared memory...\\n&quot;);\r\n\tshared_memory1_id = shmget((key_t)1234, sizeof(struct shared_memory1_struct), 0666 | IPC_CREAT);\t\t\/\/&lt;&lt;&lt;&lt;&lt; SET THE SHARED MEMORY KEY    (Shared memory key , Size in bytes, Permission flags)\r\n\t\/\/\tShared memory key\r\n\t\/\/\t\tUnique 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&#39;t guarantee to avoid colision)\r\n\t\/\/\tPermission flags\r\n\t\/\/\t\tOperation permissions \tOctal value\r\n\t\/\/\t\tRead by user \t\t\t00400\r\n\t\/\/\t\tWrite by user \t\t\t00200\r\n\t\/\/\t\tRead by group \t\t\t00040\r\n\t\/\/\t\tWrite by group \t\t\t00020\r\n\t\/\/\t\tRead by others \t\t\t00004\r\n\t\/\/\t\tWrite by others\t\t\t00002\r\n\t\/\/\t\tExamples:\r\n\t\/\/\t\t\t0666 Everyone can read and write\r\n\r\n\tif (shared_memory1_id == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;Shared memory shmget() failed\\n&quot;);\r\n\t\texit(EXIT_FAILURE);\r\n\t}\r\n\r\n\t\/\/Make the shared memory accessible to the program\r\n\tshared_memory1_pointer = shmat(shared_memory1_id, (void *)0, 0);\r\n\tif (shared_memory1_pointer == (void *)-1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;Shared memory shmat() failed\\n&quot;);\r\n\t\texit(EXIT_FAILURE);\r\n\t}\r\n\tprintf(&quot;Shared memory attached at %X\\n&quot;, (int)shared_memory1_pointer);\r\n\r\n\t\/\/Assign the shared_memory segment\r\n\tshared_memory1 = (struct shared_memory1_struct *)shared_memory1_pointer;<\/code><\/pre>\n<h5>\nReading And Writing The Shared Memory<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\t\/\/----- WRITE TO SHARED MEMORY -----\r\n\tshared_memory1-&gt;some_data[0] = 10;\r\n\tshared_memory1-&gt;some_flag = 1;\r\n\r\n\r\n\t\/\/----- READ FROM SHARED MEMORY -----\r\n\tif (shared_memory1-&gt;some_flag == 1)\r\n\t{\r\n\t\tchar our_copy = shared_memory1-&gt;some_data[0];\r\n\t}\r\n<\/code><\/pre>\n<h5>\nDeleting The Shared Memory<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\t\/\/--------------------------------\r\n\t\/\/----- DETACH SHARED MEMORY -----\r\n\t\/\/--------------------------------\r\n\t\/\/Detach and delete\r\n\tif (shmdt(shared_memory1_pointer) == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;shmdt failed\\n&quot;);\r\n\t\t\/\/exit(EXIT_FAILURE);\r\n\t}\r\n\tif (shmctl(shared_memory1_id, IPC_RMID, 0) == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;shmctl(IPC_RMID) failed\\n&quot;);\r\n\t\t\/\/exit(EXIT_FAILURE);\r\n\t}\r\n<\/code><\/pre>\n<p>\n&nbsp;\n<\/p>\n<h4>\nCreating Shared Memory WITH Semaphore Interlocking<br \/>\n<\/h4>\n<h5>\n<em>The following code works most of the time but there is a problem &#8211; in the project we used it on sometimes after power up of the RPi&nbsp;and our application&nbsp;auto running any php call to sem_get() would result in a false return&nbsp;value. &nbsp;We couldn&#39;t find the issue but suspect it may be something to do with the c&nbsp;code rather than the php code (just a hunch). &nbsp;For our project the semphore wasn&#39;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!<\/em><br \/>\n<\/h5>\n<h5>\nHeader Files Needed<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n#include &lt;sys\/shm.h&gt;\t\t\/\/Used for shared memory\r\n<\/code><\/pre>\n<h5>\nDefining&nbsp;The Shared Memory In Your Header File<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\r\n\/\/----- SEMAPHORE -----\r\n\/\/On linux systems this union is probably already defined in the included sys\/sem.h, but if not use this default basic definition:\r\nunion semun {\r\n\tint val;\r\n\tstruct semid_ds *buf;\r\n\tunsigned short *array;\r\n};\r\n\r\n\/\/FUNCTIONS:\r\nstatic int semaphore1_get_access(void);\r\nstatic int semaphore1_release_access(void);\r\n\/\/VARIABLES:\r\nstatic int semaphore1_id;\r\n\r\n\/\/----- SHARED MEMORY -----\r\nstruct shared_memory1_struct {\r\n\tint some_flag;\r\n\tchar some_data[1024];\r\n};\r\n\r\nvoid *shared_memory1_pointer = (void *)0;\r\n\/\/VARIABLES:\r\nstruct shared_memory1_struct *shared_memory1;\r\nint shared_memory1_id;\r\n<\/code><\/pre>\n<h5>\nThe Semaphore Functions<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\r\n\/\/***********************************************************\r\n\/\/***********************************************************\r\n\/\/********** WAIT IF NECESSARY THEN LOCK SEMAPHORE **********\r\n\/\/***********************************************************\r\n\/\/***********************************************************\r\n\/\/Wait if necessary and then change the semaphore by &ndash;1. This is the &quot;wait&quot; operation\r\nstatic int semaphore1_get_access(void)\r\n{\r\n\tstruct sembuf sem_b;\r\n\tsem_b.sem_num = 0;\r\n\tsem_b.sem_op = -1; \/* P() *\/\r\n\tsem_b.sem_flg = SEM_UNDO;\r\n\tif (semop(semaphore1_id, &amp;sem_b, 1) == -1)\t\t\/\/Wait until free\r\n\t{\r\n\t\tfprintf(stderr, &quot;semaphore1_get_access failed\\n&quot;);\r\n\t\treturn(0);\r\n\t}\r\n\treturn(1);\r\n}\r\n\r\n\/\/***************************************\r\n\/\/***************************************\r\n\/\/********** RELEASE SEMAPHORE **********\r\n\/\/***************************************\r\n\/\/***************************************\r\n\/\/Setting the semaphore back to available.  This is the &quot;release&quot; operation.\r\n\r\nstatic int semaphore1_release_access(void)\r\n{\r\n\tstruct sembuf sem_b;\r\n\tsem_b.sem_num = 0;\r\n\tsem_b.sem_op = 1; \/* V() *\/\r\n\tsem_b.sem_flg = SEM_UNDO;\r\n\tif (semop(semaphore1_id, &amp;sem_b, 1) == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;semaphore1_release_access failed\\n&quot;);\r\n\t\treturn(0);\r\n\t}\r\n\treturn(1);\r\n}\r\n<\/code><\/pre>\n<h5>\nCreating The Shared Memory<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\r\n\t\/\/-----------------------------------------------\r\n\t\/\/----- CREATE SHARED MEMORY WITH SEMAPHORE -----\r\n\t\/\/-----------------------------------------------\r\n\tprintf(&quot;Creating shared memory with semaphore...\\n&quot;);\r\n\tsemaphore1_id = semget((key_t)12345, 1, 0666 | IPC_CREAT);\t\t\/\/&lt;&lt;&lt;&lt;&lt; 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)\r\n\t\/\/\tSemaphore key\r\n\t\/\/\t\tUnique 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&#39;t guarantee to avoid colision)\r\n\r\n\t\/\/Initialize the semaphore using the SETVAL command in a semctl call (required before it can be used)\r\n\tunion semun sem_union_init;\r\n\tsem_union_init.val = 1;\r\n\tif (semctl(semaphore1_id, 0, SETVAL, sem_union_init) == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;Creating semaphore failed to initialize\\n&quot;);\r\n\t\texit(EXIT_FAILURE);\r\n\t}\r\n\t\r\n\tshared_memory1_id = shmget((key_t)1234, sizeof(struct shared_memory1_struct), 0666 | IPC_CREAT);\t\t\/\/&lt;&lt;&lt;&lt;&lt; SET THE SHARED MEMORY KEY    (Shared memory key , Size in bytes, Permission flags)\r\n\t\/\/\tShared memory key\r\n\t\/\/\t\tUnique 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&#39;t guarantee to avoid colision)\r\n\t\/\/\tPermission flags\r\n\t\/\/\t\tOperation permissions \tOctal value\r\n\t\/\/\t\tRead by user \t\t\t00400\r\n\t\/\/\t\tWrite by user \t\t\t00200\r\n\t\/\/\t\tRead by group \t\t\t00040\r\n\t\/\/\t\tWrite by group \t\t\t00020\r\n\t\/\/\t\tRead by others \t\t\t00004\r\n\t\/\/\t\tWrite by others\t\t\t00002\r\n\t\/\/\t\tExamples:\r\n\t\/\/\t\t\t0666 Everyone can read and write\r\n\r\n\tif (shared_memory1_id == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;Shared memory shmget() failed\\n&quot;);\r\n\t\texit(EXIT_FAILURE);\r\n\t}\r\n\r\n\t\/\/Make the shared memory accessible to the program\r\n\tshared_memory1_pointer = shmat(shared_memory1_id, (void *)0, 0);\r\n\tif (shared_memory1_pointer == (void *)-1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;Shared memory shmat() failed\\n&quot;);\r\n\t\texit(EXIT_FAILURE);\r\n\t}\r\n\tprintf(&quot;Shared memory attached at %X\\n&quot;, (int)shared_memory1_pointer);\r\n\r\n\t\/\/Assign the shared_memory segment\r\n\tshared_memory1 = (struct shared_memory1_struct *)shared_memory1_pointer;\r\n<\/code><\/pre>\n<h5>\nReading And Writing The Shared Memory<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\r\n\t\/\/----- SEMAPHORE GET ACCESS -----\r\n\tif (!semaphore1_get_access())\r\n\t\texit(EXIT_FAILURE);\r\n\r\n\t\/\/----- READ \/ WRITE FROM SHARED MEMORY -----\r\n\tif (shared_memory1-&gt;some_flag == 1)\r\n\t{\r\n\t\tshared_memory1-&gt;some_data[0] = 10;\r\n\t\tshared_memory1-&gt;some_flag = 0;\r\n\t}\r\n\r\n\t\/\/----- SEMAPHORE RELEASE ACCESS -----\r\n\tif (!semaphore1_release_access())\r\n\t\texit(EXIT_FAILURE);\r\n\r\n<\/code><\/pre>\n<h5>\nDeleting The Shared Memory<br \/>\n<\/h5>\n<pre>\r\n<code>\r\n\t\/\/--------------------------------\r\n\t\/\/----- DETACH SHARED MEMORY -----\r\n\t\/\/--------------------------------\r\n\t\/\/Detach and delete\r\n\tif (shmdt(shared_memory1_pointer) == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;shmdt failed\\n&quot;);\r\n\t\t\/\/exit(EXIT_FAILURE);\r\n\t}\r\n\tif (shmctl(shared_memory1_id, IPC_RMID, 0) == -1)\r\n\t{\r\n\t\tfprintf(stderr, &quot;shmctl(IPC_RMID) failed\\n&quot;);\r\n\t\t\/\/exit(EXIT_FAILURE);\r\n\t}\r\n\t\/\/Delete the Semaphore\r\n\t\/\/It&#39;s important not to unintentionally leave semaphores existing after program execution. It also may cause problems next time you run the program.\r\n\tunion semun sem_union_delete;\r\n\tif (semctl(semaphore1_id, 0, IPC_RMID, sem_union_delete) == -1)\r\n\t\tfprintf(stderr, &quot;Failed to delete semaphore\\n&quot;);\r\n<\/code><\/pre>\n<h4>\nDebugging<br \/>\n<\/h4>\n<p>\nCommand line list shared memory:\n<\/p>\n<pre>\r\n<code>ipcs -m<\/code><\/pre>\n<p>\nCommand line list semaphores:\n<\/p>\n<pre>\r\n<code>ipcs -s<\/code><\/pre>\n<p>\n&nbsp;\n<\/p>\n<h4>\nShared Memory Between A C&nbsp;Application And PHP Web Server<br \/>\n<\/h4>\n<p>\nSee <a href=\"https:\/\/raspberry-projects.com\/pi\/programming-in-c\/memory\/shared-memory-between-c-application-and-php-web-server\">here<\/a>.\n<\/p>\n<p>\n&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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.&nbsp;The only catch is that by [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[],"class_list":["post-748","post","type-post","status-publish","format-standard","hentry","category-memory"],"_links":{"self":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/comments?post=748"}],"version-history":[{"count":16,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/748\/revisions"}],"predecessor-version":[{"id":2868,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/748\/revisions\/2868"}],"wp:attachment":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/media?parent=748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/categories?post=748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/tags?post=748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}