共享内存是有IPC为进程创建的一个特殊的地址范围,它将出现在该进程的地址的空间中。
共享内存使用的函数类似与信号量的函数,它的定义如下:
#include<sys/shm.h>
void *shmat(int shm_id , const void *shm_addr , int shmflg);
int shmctl(int shm_id , int cmd , struct shmid_ds *buf);
int shmdt(const void *shm_addr);
int sgmget(key_t key , size_t size , int shmflg);
1.shmget函数
int sgmget(key_t key , size_t size , int shmflg);
与信号量一样,程序需要提供一个参数key,它有效地共享内存段命名、shmget函数返回一个共享内存标识符,该标识符将用于后续的共享内存函数。有一个特殊的键值IPC_PRIVATE,它用于创建一个值属于创建进程的共享内存、
第二个参数size以字节为单位指定需要共享的内存的容量。
第三个参数shmflg包含9个比特的权限标识,他们的作用与创建文件时使用的mode标志一样。
2.shmat函数
第一次创建共享内存段时,它不能被任何进程访问。要想启用对该共享内存的访问,必须将其连接到一个进程的地址空间中。这项任务由shmat完成。
void *shmat(int shm_id , const void *shm_addr , int shmflg);
第一个参数shm_id是由shmget返回的共享内存标示符。
第二个参数shm_addr指定的是共享内存连接到当前进程中的地址位置。
第三个参数shmflg是一组位标志,它的两个取值是SHM_RND(这个标志与shm_addr联合使用,用来控制共享内存连接的地址)和SHM_RDONLY(它使得连接的内存只读)。
如果shmat调用成功,它返回一个指向共享内存第一个字节的指针。如果失败,它就返回-1.
3.shmdt函数
它的作用是将共享内存从当前进程中分离。注意,分离共享内存并未删除它,只是使得该共享内存对当前进程不再可用。
4.shmctl
与复杂的信号量控制函数相比,共享内存的控制函数要稍微简单一下。
int shmctl(int shm_id , int cmd , struct shmid_ds *buf);
shmid_ds结构至少包含以下成员:
struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
}
第一个参数shm_id是shmget返回的共享内存标识符。
第二个参数command是采取的动作,它可以取三个值
IPC_STAT 把shmid_ds结构中的数据设置为共享内存的当前关联值。
IPC_SET 如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值、
IPC_RMID 删除共享内存段
第三个参数buf是一个指针,它指向包含共享内存模式和访问权限的结构。
/* Our first program is a consumer. After the headers the shared memory segment (the size of our shared memory structure) is created with a call to shmget, with the IPC_CREAT bit specified. */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/shm.h> #include "shm_com.h" int main() { int running = 1; void *shared_memory = (void *)0; struct shared_use_st *shared_stuff; int shmid; srand((unsigned int)getpid()); shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT); if (shmid == -1) { fprintf(stderr, "shmget failed\n"); exit(EXIT_FAILURE); } /* We now make the shared memory accessible to the program. */ shared_memory = shmat(shmid, (void *)0, 0); if (shared_memory == (void *)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("Memory attached at %X\n", (int)shared_memory); /* The next portion of the program assigns the shared_memory segment to shared_stuff, which then prints out any text in written_by_you. The loop continues until end is found in written_by_you. The call to sleep forces the consumer to sit in its critical section, which makes the producer wait. */ shared_stuff = (struct shared_use_st *)shared_memory; shared_stuff->written_by_you = 0; while(running) { if (shared_stuff->written_by_you) { printf("You wrote: %s", shared_stuff->some_text); sleep( rand() % 4 ); /* make the other process wait for us ! */ shared_stuff->written_by_you = 0; if (strncmp(shared_stuff->some_text, "end", 3) == 0) { running = 0; } } } /* Lastly, the shared memory is detached and then deleted. */ if (shmdt(shared_memory) == -1) { fprintf(stderr, "shmdt failed\n"); exit(EXIT_FAILURE); } if (shmctl(shmid, IPC_RMID, 0) == -1) { fprintf(stderr, "shmctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
/* The second program is the producer and allows us to enter data for consumers. It's very similar to shm1.c and looks like this. */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/shm.h> #include "shm_com.h" int main() { int running = 1; void *shared_memory = (void *)0; struct shared_use_st *shared_stuff; char buffer[BUFSIZ]; int shmid; shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT); if (shmid == -1) { fprintf(stderr, "shmget failed\n"); exit(EXIT_FAILURE); } shared_memory = shmat(shmid, (void *)0, 0); if (shared_memory == (void *)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("Memory attached at %X\n", (int)shared_memory); shared_stuff = (struct shared_use_st *)shared_memory; while(running) { while(shared_stuff->written_by_you == 1) { sleep(1); printf("waiting for client...\n"); } printf("Enter some text: "); fgets(buffer, BUFSIZ, stdin); strncpy(shared_stuff->some_text, buffer, TEXT_SZ); shared_stuff->written_by_you = 1; if (strncmp(buffer, "end", 3) == 0) { running = 0; } } if (shmdt(shared_memory) == -1) { fprintf(stderr, "shmdt failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }