- ftok()简介
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
ftok原型如下:
key_t ftok( char * fname, int id )
fname就时你指定的文件名,id是子序号。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。
如果要确保key_t值不变,要目确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值。
另外说一句:在aix等操作系统上,有多个文件系统,会出现分布在不同的文件系统上的两个文件具有相同的索引节点号,此时用ftok对这两个文件进行操作,只要id参数不变,得到的key_t值相同,造成创建消息队列失败。不过这种情况相当少见罢了。
- #define IPCKEY 0x111
- char path[256];
- sprintf( path, "%s/etc/config.ini", (char*)getenv("HOME") );
- msgid=ftok( path, IPCKEY );
2使用信号量
要使用共享内存,应该有如下步骤:
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来删除共享内存区
系统5里面的ipc,通信的时候使用ipc对象,是内核创建的,
在内存之中。
在程序关闭时,pipe已经关闭不存在了,fifo是实际存在的文件。程序结束时
Fifo的内容被释放掉。
Ipc包括:share memory,message queue,semaphore
Pipe通过继承找到要打开的文件。
Fifo通过文件路径找到要打开的文件。
头文件:sys/ipc.h sys/types.h sys/shm.h
使用key来创建ipc的id
Ftok()让不同的进程找到同一个key
Key_t ftok (char *pathname,char proj);
只要相同使用该函数,就会得到统一的key。
成返:key,失败返-1
Proj随便指定
1. 创建key
2. 用key创建ipc
3. 打开。。。。
Key_t key=ftok(“/home/linux”,1);
共享内存:效率最高的进程通信方式。不需要任何内存的拷贝。
由于多个进程共享,所以要使用同步机制,如互斥锁,信号量。
共享内存实现:
1. 创建共享内存,shmget创建或打开共享内存。
Int shmget(key_t key,int size,int shmflg);
Ftok(IPC_PRIVATE,…..);
如果使用IPC_PRIVATE,只能自己使用,其他人不能使用。
Size:共享内存大小。
Shmflg:权限位。0666|IPC_CREAT|IPC_EXCL
如果flg同时指定了IPC_CREAT 和 IPC_EXCL,存在就报错。
IPC_CREAT创建一个共享内存。
当执行成功:返shmid整型的,
2. 映射到。。。。。。shmat(映射共享内存,就是把这个共享内存映射到具体的进程空间中去)
Void *shmat(int shmid,const void * shmaddr,int shflg);
Shmid:shmget的返回值。要映射的共享内存标识符
Shmaddr:将共享内存映射到指定地址(若为0则表示该段共享内存映射到调用进程的地址空间
使用不带缓冲的io进行读写。
Nattach 被映射的进程的个数
3. 取消映射。Shdmdt
Int shmdt(const void *shmaddr);
Shmaddr:被映射的共享内存段地址。
成功返0,失败-1
4. 删除共享内存(不删除就会一直存在与共享内存)shmctl
Int shmctl(int shmid,int cmd,struct shmid_ds *buf);
Cmd:IPC_STAT,IPC_SET,IPC_RMID
Shmctl(shmid, IPC_RMID , NULL);
Ipcrm -h