共享内存---shmget shmat shmdt

本文详细介绍了如何使用共享内存进行进程间通信,包括通过ftok()计算标识符、使用shmget()开辟共享内存、shmat()允许进程访问共享内存、shmdt()禁止进程访问以及shmctl()和ipcrm命令控制和删除共享内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.chinaunix.net/u/12592/showart_1133307.html

 

要使用共享内存,应该有如下步骤:
1.开辟一块共享内存 shmget()
2.允许本进程使用共某块共享内存 shmat()
3.写入/读出
4.禁止本进程使用这块共享内存 shmdt()
5.删除这块共享内存 shmctl()或者命令行下ipcrm


ftok()。它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。

shmkey = ftok( "mcut" , 'a' ); // 计算标识符

操作共享内存,我们用到了下面的函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget( key_t shmkey , int shmsiz , int flag );
void *shmat( int shmid , char *shmaddr , int shmflag );
int shmdt( char *shmaddr );

shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:
key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。
int shmsiz 是这块内存的大小.
int flag 是这块内存的模式(mode)以及权限标识。
模式可取如下值: 新建:IPC_CREAT
使用已开辟的内存:IPC_ALLOC
如果标识符以存在,则返回错误值:IPC_EXCL
然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。
如: IPC_CREAT | IPC_EXCL | 0666
这个函数成功时返回共享内存的ID,失败时返回-1。

// shmid开辟共享内存

shmid = shmget( shmkey , sizeof(in_data) , IPC_CREAT | 0666 ) ;


shmat()是用来允许本进程访问一块共享内存的函数。
int shmid是那块共享内存的ID。
char *shmaddr是共享内存的起始地址
int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回-1。

char *head , *pos ,

head = pos = shmat( shmid , 0 , 0 );

// 允许本进程使用这块共享内存

shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。
参数char *shmaddr是那块共享内存的起始地址。
成功时返回0。失败时返回-1。

shmdt( head ); // 禁止本进程使用这块内存

此外,还有一个用来控制共享内存的shmctl()函数如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl( int shmid , int cmd , struct shmid_ds *buf );
int shmid是共享内存的ID。
int cmd是控制命令,可取值如下:
IPC_STAT 得到共享内存的状态
IPC_SET 改变共享内存的状态
IPC_RMID 删除共享内存
struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。
返回值: 成功:0
失败:-1

shmctl(shmid,IPC_RMID,NULL);

刚才我们的mpaste.c程序中还可以加入这样几句。

struct shmid_ds buf;
... ...
shmctl( shmid , IPC_STAT , &buf ); // 取得共享内存的状态
... ...
shmctl( shmid , IPC_RMID , &buf ); // 删除共享内存

注意:在使用共享内存,结束程序退出后。如果你没在程序中用shmctl()删除共享内存的话,一定要在命令行下用ipcrm命令删除这块共享内存。你要是不管的话,它就一直在那儿放着了。
简单解释一下ipcs命令和ipcrm命令。

取得ipc信息:
ipcs [-m|-q|-s]
-m 输出有关共享内存(shared memory)的信息
-q 输出有关信息队列(message queue)的信息
-s 输出有关“遮断器”(semaphore)的信息
%ipcs -m

删除ipc
ipcrm -m|-q|-s shm_id
%ipcrm -m 105

例如,我们在以0x12345678为KEY创建了一个共享内存,可以直接使用ipcrm -M 0x12345678来删除共享内存区域。


参考:
http://hylcarson.blog.sohu.com/54735006.html
http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index2.html


### 创建共享内存的C语言示例 为了创建并访问共享内存,在C程序中通常会使用`ftok()`来生成键值,接着利用此键通过`shmget()`获取或创建一个共享内存段,最后调用`shmat()`将该段附加到当前进程中。 #### 使用 `ftok()`, `shmget()`, 和 `shmat()` 的具体实现如下: ```c #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> /* ftok */ #include <sys/shm.h> /* shmget, shmat */ #define SHM_KEY_PATH "/tmp" #define PROJ_ID 'A' int main() { key_t key; int shmid; char *data; // Generate a unique key for IPC objects. if ((key = ftok(SHM_KEY_PATH, PROJ_ID)) == -1) { perror("Failed to generate key"); exit(EXIT_FAILURE); } // Create or get an existing shared memory segment associated with the key. if ((shmid = shmget(key, 1024, 0644 | IPC_CREAT)) == -1) { perror("Shared memory creation failed"); exit(EXIT_FAILURE); } // Attach the shared memory segment to this process's address space. data = (char*)shmat(shmid, NULL, 0); if(data == (char *)(-1)){ perror("Attach operation failed"); exit(EXIT_FAILURE); } printf("Data attached at %p\n", data); strcpy(data,"Hello Shared Memory"); // Detach from shared memory when done. if(shmdt(data)==-1){ perror("Detach operation failed"); exit(EXIT_FAILURE); } return 0; } ``` 上述代码展示了如何初始化共享内存区,并向其中写入字符串。这里需要注意的是,当完成对共享内存的操作之后应当显式地将其分离[^1]。 #### 关于共享内存管理的一些注意事项 - 当多个进程需要通信时可以共同访问同一块由`shmget()`返回ID所代表的共享内存区域。 - 如果指定了`(void *)0`作为第二个参数传递给`shmat()`函数,则操作系统会选择合适的地址空间位置来进行映射;这通常是推荐的做法除非有特殊需求。 - 对于不再使用的共享内存应该及时销毁它以释放资源,可以通过`shmctl()`接口指定删除操作来达到目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值