进程中的标识符和键(ftok函数创建)(共享内存,消息队列,信号量用到的)

每个内核中的IPC结构(消息队列、信号量和共享内存)都用一个非负整数的标识符(identifier)加以引用。

    也就是说,一个非负整数代表一个IPC结构。  

比如,为了对一个消息队列发送或者取消息,只需要知道其队列标识符,与文件描述符不同,IPC标识符不是小的正数。当一个IPC结构被创建,以后又被删除,与这种结构相关的标识符连续加1,直到达到整型数的最大正直,然后又回到0

对于同一个IPC结构,为了使多个进程都能获取标识符ID指向这个IPC结构,需要大家都能访问到文件路径和项目id来创建一个东西,拿这个东西来生成IPC的结构,这个东西就是:

键(key)。

举个例子,不同的人都想进同一个带锁的房间交流,是不是都需要相同钥匙打开?

 

1.键(key)的创建(使用ftok函数)

每次创建IPC结构,都必须指定一个键,键的数据类型是基本系统数据类型key_t,通常在头文件<sys/types.h>中,定位为整型(《Unix环境高级编程》说是长整型,但我编译时发现是整型)。键由内核变换成标识符。

 

       #include <sys/types.h>

       #include <sys/ipc.h>

 

       key_t ftok(const char *pathname, int proj_id);

 

ftok根据提供的路径pathname和项目proj_id生成一个键,如果返回-1,则出错。

值得一提的是,ftok可能会返回一个负数,只要不是-1就是有效的key

ftok函数只使用proj_id的低8位(0255的值),也就是说proj_id不管值多大,也只取最低8位。

pathname必须是一个有效的路径及可访问的。

 

生成的key是留给semget,msgget,shmget使用的。

一个key和一个整型的flag,满足以下条件之一,就创建一个新的IPC结构:

(1)keyIPC_PRIVATE

(2)key当前未与特定类型的IPC结构相结合,并且flag中指定了IPC_CREAT

 

如果希望创建一个新的IPC结构,而且要确保不是引用具有同一标识符的一个现已存在的IPC结构,那么必须在flag中同时指定IPC_CREATIPC_EXCL位,加上这两个标志位后,如果IPC结构已经存在,就是导致创建出错,返回EEXIST

 

如果访问一个现存的IPC结构,就必须知道与IPC结构相结合的标识符ID,通过ID去访问,

并且创建的键值不能 IPC_PRIVATE,因为 IPC_PRIVATE是拿来创建一个key的。

 

 

 

2.自己实现一个键的创建

ftok创建的键一般由以下方式构成:按给定的路径名取其stat结构,从该结构中取出部分st_devst_ino字段,然后再与项目ID组合起来,如果两个路径名引用不同的文件,那么对这两个路径名调用ftok通常返回不同的键。但是因为i节点号和键通常都放在长整型中,于是创建键时可能会丢失信息。这意味着如果使用同一项目ID,那么对于不同文件的两个路径名可能产生相同的键。

以下程序展示了键的创建原理:


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>	
#define ProgramId (0x11&0x00ff) 
int main()
{
	
	key_t ftok_key=-1;
	struct stat stuStat; 
	ftok_key = ftok("/share/1.tmp",ProgramId);
	printf("\n ftok_key[0x%x] errno=%d	[%s]\n",ftok_key,errno,strerror(errno));

	memset(&stuStat,0,sizeof(struct stat));
	stat("/share/1.tmp",&stuStat);
	
	printf("\n st_dev[0x%x]  st_ino[0x%x] ProgramId[0x%x] \n",
		(unsigned int )stuStat.st_dev,(unsigned int )stuStat.st_ino,ProgramId);
	
	return 0;
}


运行结果:

root@ubuntu:/share# gcc test_ftok.c

root@ubuntu:/share#

root@ubuntu:/share#

root@ubuntu:/share#

root@ubuntu:/share# ./a.out         

 

 ftok_key[0x11014d87] errno=0   [Success]

 

 st_dev[0x801]  st_ino[0x64d87] ProgramId[0x11]

root@ubuntu:/share#

 

从结果来看,函数ftok产生的键值就是取ProgramId的低8bitst_dev的后8bitst_ino16bit,组成一个32位的整数。

 

附带提下stat函数和结构体:

#include <sys/types.h>

       #include <sys/stat.h>

       #include <unistd.h>

 

       int stat(const char *pathname, struct stat *buf);

 

  struct stat {

       dev_t  st_dev;  /* ID of device containing file */

       ino_t  st_ino;  /* inode number */

       mode_t  st_mode;  /* protection */

       nlink_t  st_nlink;  /* number of hard links */

       uid_t  st_uid;  /* user ID of owner */

       gid_t  st_gid;  /* group ID of owner */

       dev_t  st_rdev;  /* device ID (if special file) */

       off_t  st_size;  /* total size, in bytes */

       blksize_t st_blksize;  /* blocksize for filesystem I/O */

       blkcnt_t  st_blocks;  /* number of 512B blocks allocated */

 

       /* Since Linux 2.6, the kernel supports nanosecond

  precision for the following timestamp fields.

  For the details before Linux 2.6, see NOTES. */

 

       struct timespec st_atim;  /* time of last access */

       struct timespec st_mtim;  /* time of last modification */

       struct timespec st_ctim;  /* time of last status change */

 

   #define st_atime st_atim.tv_sec /* Backward compatibility */

   #define st_mtime st_mtim.tv_sec

   #define st_ctime st_ctim.tv_sec

   };

 

st_dev属于long long unsigned int类型

st_ino属于long unsigned int类型







使用的ftok注意防范隐患

由于ftok函数是根据路径的i节点和设备id、项目id来生成键值的,所以在ftok创建的键值,生成的进程ipc结构标识符后,不要去删除路径,然后再次生成路径,因为i节点可能会发生变化,导致另外进程生成的键值不一样,无法进行消息队列通信、共享内存、信号量等,这是非常大的隐患,如果产生bug,将会非常难查。



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值