{"id":220,"date":"2008-01-02T14:02:44","date_gmt":"2008-01-02T20:02:44","guid":{"rendered":"http:\/\/www.lastdragon.net\/?p=220"},"modified":"2014-04-26T12:12:46","modified_gmt":"2014-04-26T18:12:46","slug":"reservado-5","status":"publish","type":"post","link":"https:\/\/www.lastdragon.net\/?p=220","title":{"rendered":"Memoria Compartida en C y GNU\/Linux"},"content":{"rendered":"<p>La memoria compartida es muy \u00fatil para programas que subprocesos con fork, sin embargo no necesariamente es ese su l\u00edmite, la memoria compartida igual puede ser usada por programas totalmente distintos como un medio para enviarse se\u00f1ales y compartir informaci\u00f3n en com\u00fan.<\/p>\n<p>Solo hay un problema, todo kernel decente tiene protecci\u00f3n de memoria, esto significa que un programa no puede interferir con otro, as\u00ed que el hecho de que 2 o m\u00e1s programas intenten entrar a la misma zona de memoria es contradictorio, por lo que el sistema operativo as\u00ed de gusto no lo va a permitir, salvo sea el mismo sistema operativo quien nos ayude a esto.<\/p>\n<p>Para mostrar c\u00f3mo es posible hacer esto, hare 3 programas, podr\u00edan ser al menos 2, pero la intenci\u00f3n es mostrar que muchos programas pueden operar con los mismos segmentos de memoria.<\/p>\n<p>El primer programa reservada la memoria y ser\u00e1 el encargado de liberarla tambi\u00e9n, mientras este programa este corriendo los otros 2 podr\u00e1n accesar a la memoria compartida.<\/p>\n<p>El segundo programa accesara a la memoria compartida e ir\u00e1 haciendo modificaciones en dicha zona, ser\u00e1 un contador.<\/p>\n<p>El tercer programa leer\u00e1 la zona de memoria y nos mostrara el valor actual que hay en ella.<\/p>\n<p>Los 3 programas ser\u00e1n muy similares, las funciones se explican a continuaci\u00f3n.<\/p>\n<p>Para que programas completamente independientes compartan informaci\u00f3n, deben tener un acceso com\u00fan a un recursos del sistema, estos programas crean si no existe un archivo en el temporal y se ligaran a el para crear una llave<\/p>\n<p>La llave se asigna a una variable tipo key_t usando la funci\u00f3n ftok, ftok requiere 2 parametros , el archivo en com\u00fan que hemos creado y un entero, esto debe coincidir en cada programa que vaya a usar la zona de memoria, de lo contrario el sistema operativo les negara el acceso tal cual debe ser.<\/p>\n<p>Obtenemos la clave con el siguiente ejemplo.<\/p>\n<p>key_t clavecompartida = ftok (&#8220;\/tmp\/acompartido&#8221;,33);<\/p>\n<p>una vez con la clave solicitamos al sistema operativo cree una zona de memoria de 400 bytes, un apuntador tipo char de 100 veces su tama\u00f1o. Esto nos devolver\u00e1 un entero con el identificador del segmento de memoria, si la asignaci\u00f3n tuvo \u00e9xito.<br \/>\nint mem = shmget (clavecompartida,sizeof(char *)*100,0777 | IPC_CREAT);<\/p>\n<p>N\u00f3tese que la protecci\u00f3n de memoria es similar a la protecci\u00f3n de acceso a archives, el par\u00e1metro 0777 tiene el mismo significado que los permisos de archivo, de esta forma  estamos declarando que nuestra memoria ser\u00e1 de acceso total para todos, tambi\u00e9n podr\u00edamos dar permisos de solo lectura para determinados programas que corran con X usuario, como solo lectura o negarle el acceso a cualquier otro usuario que quiera entrar a nuestra memoria compartida, el IPC_CREAT Solo lo usamos al momento de buscar reservar o crear el espacio, para leer o modificar la memoria en otros programas no ser\u00e1 necesario, porque ya existir\u00e1.<\/p>\n<p>Ya con el identificador entraremos a la zona de memoria v\u00eda punteros, al puntero lo alimentamos con la funci\u00f3n shmat a la cual le pasamos como par\u00e1metro el identificador de nuestra zona de memoria<\/p>\n<p>char *mcompartida = (char *) shmat (mem,NULL,0);<\/p>\n<p>En este punto, el puntero char mcompartida est\u00e1 ligado a la memoria compartida y lo que le hagamos a ese puntero, lo estamos haciendo en esa zona de memoria.<\/p>\n<p>Aclarando que es mas f\u00e1cil mover cadenas de caracteres por ese punto, por lo que si queremos pasar n\u00fameros, por ejemplo un 10, sera mas f\u00e1cil enviar una cadena de caracteres \u201c10\u201d y al recibirla en otro programa, convertirla en un entero, por ejemplo<\/p>\n<p>Strcpy (mcompartida,\u201d10\u201d);<\/p>\n<p>Liberando la memoria compartida y borrando el archivo en com\u00fan, con la funci\u00f3n shmctl y pas\u00e1ndole el primer par\u00e1metro la variable entera que tiene el identificador de la zona de memoria<\/p>\n<p>shmctl (mem, IPC_RMID, (struct shmid_ds *)NULL);<\/p>\n<p>unlink (\u201carchivo\u201d);<\/p>\n<p>unlink borra archives del sistema operativo<\/p>\n<p>Si el programa terminara de forma incorrecta o por interrupci\u00f3n del usuario, la memoria compartida se quedara en el sistema operativo indefinidamente, ya que el programa nunca le notifico al sistema operativo que deb\u00eda liberarla.<\/p>\n<p>En el caso de GNU\/Linux los comandos ipcs  nos ayudaran a administrar manualmente las zonas compartidas de memoria.<\/p>\n<p>Si queremos ver cu\u00e1ntas memorias compartidas hay, usamos el comando ipcs<\/p>\n<p>Por ejemplo si queremos borrar la zona 1234 usamos el Ipcrm \u2013m 1234<\/p>\n<p>Ahora el c\u00f3digo de 3 programas que demuestran el acceso a la memoria compartida.<\/p>\n<p>Asignar.c Este programa reserva y libera la memoria, mientras se ejecute los otros 2 programas tendr\u00e1n acceso a la memoria.<br \/>\n#include &lt;stdio.h&gt;<br \/>\n#include &lt;sys\/shm.h&gt;<\/p>\n<p>int main ()<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE *archivocompartido;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_t clavecompartida;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int mem = 0;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *mcompartida = NULL;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; archivocompartido = fopen<br \/>\n(&#8220;\/tmp\/acompartido&#8221;,&#8221;w+&#8221;);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clavecompartida = ftok<br \/>\n(&#8220;\/tmp\/acompartido&#8221;,33);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem = shmget<br \/>\n(clavecompartida,sizeof(char *)*100,0777 | IPC_CREAT);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mcompartida = (char *) shmat<br \/>\n(mem,NULL,0);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf (&#8220;Creando el segmento<br \/>\n%d de memoria compartida\\n\\n&#8221;,mem);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf (&#8220;Precione ENTER para<br \/>\nliberar los recursos compartidos\\n&#8221;);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getchar ();<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shmctl (mem, IPC_RMID,<br \/>\n(struct shmid_ds *)NULL);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unlink (&#8220;\/tmp\/acompartido&#8221;);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br \/>\n}<\/p>\n<p>Modificar.c Este programa modifica la zona de memoria asignada por asignar.c<br \/>\n#include &lt;stdio.h&gt;<br \/>\n#include &lt;sys\/shm.h&gt;<\/p>\n<p>int main ()<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE *archivocompartido;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_t clavecompartida;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int mem = 0;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int contador = 0;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *mcompartida = NULL;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; archivocompartido = fopen<br \/>\n(&#8220;\/tmp\/acompartido&#8221;,&#8221;w+&#8221;);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clavecompartida = ftok<br \/>\n(&#8220;\/tmp\/acompartido&#8221;,33);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem =&nbsp; shmget<br \/>\n(clavecompartida,sizeof(char *)*100,0777);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mcompartida = (char *)&nbsp;<br \/>\nshmat (mem,NULL,0);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf (&#8220;Trabjando con el<br \/>\nsegmento: %d\\n&#8221;,mem);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf (&#8220;Cada segundo se<br \/>\nactualiza el valor compartido, el programa dura un minuto\\n&#8221;);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (contador != 60)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br \/>\ncontador = contador + 1;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br \/>\nsprintf (mcompartida,&#8221;%d&#8221;,contador);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br \/>\nsleep (1);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br \/>\n}<br \/>\nObtener.c este programa obtiene el valor actual de la zona de memoria compartida<\/p>\n<p>#include &lt;stdio.h&gt;<br \/>\n#include &lt;sys\/shm.h&gt;<\/p>\n<p>int main ()<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE *archivocompartido;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_t clavecompartida;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int mem = 0;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *mcompartida = NULL;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; archivocompartido = fopen<br \/>\n(&#8220;\/tmp\/acompartido&#8221;,&#8221;w+&#8221;);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clavecompartida = ftok<br \/>\n(&#8220;\/tmp\/acompartido&#8221;,33);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem =&nbsp; shmget<br \/>\n(clavecompartida,sizeof(char *)*100,0777);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mcompartida = (char *)&nbsp;<br \/>\nshmat (mem,NULL,0);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf (&#8220;Trabajando con el<br \/>\nsegmento: %d\\n&#8221;,mem);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf (&#8220;El valor compartido<br \/>\nes: %s\\n&#8221;, mcompartida);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br \/>\n}<\/p>\n<p>Un video mostrando la ejecuci\u00f3n de los 3 c\u00f3digos.<\/p>\n<p><iframe loading=\"lazy\" width=\"420\" height=\"315\" src=\"\/\/www.youtube.com\/embed\/szEqSHd-FRc\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>Codigo fuente<br \/>\nhttps:\/\/www.lastdragon.net\/misarchivos\/memcompartida.tar.gz<\/p>\n","protected":false},"excerpt":{"rendered":"<p>La memoria compartida es muy \u00fatil para programas que subprocesos con fork, sin embargo no necesariamente es ese su l\u00edmite, la memoria compartida igual puede ser usada por programas totalmente distintos como un medio para enviarse se\u00f1ales y compartir informaci\u00f3n en com\u00fan. Solo hay un problema, todo kernel decente tiene protecci\u00f3n de memoria, esto significa&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-220","post","type-post","status-publish","format-standard","hentry","category-programacion"],"_links":{"self":[{"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=\/wp\/v2\/posts\/220","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=220"}],"version-history":[{"count":1,"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=\/wp\/v2\/posts\/220\/revisions"}],"predecessor-version":[{"id":1022,"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=\/wp\/v2\/posts\/220\/revisions\/1022"}],"wp:attachment":[{"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lastdragon.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}