ftok的陷阱
根据pathname指定的文件(或目录)名称,以及proj_id参数指定的数字,ftok函数为IPC对象生成一个唯一性的键值。在实际应用中,很容易产生的一个理解是,在proj_id相同的情况下,只要文件(或目录)名称不变,就可以确保ftok返回始终一致的键值。然而,这个理解并非完全正确,有可能给应用开发埋下很隐晦的陷阱。因为ftok的实现存在这样的风险,即在访问同一共享内存的多个进程先后调用ftok函数的时间段中,如果pathname指定的文件(或目录)被删除且重新创建,则文件系统会赋予这个同名文件(或目录)新的i节点信息,于是这些进程所调用的ftok虽然都能正常返回,但得到的键值却并不能保证相同。由此可能造成的后果是,原本这些进程意图访问一个相同的共享内存对象,然而由于它们各自得到的键值不同,实际上进程指向的共享内存不再一致;如果这些共享内存都得到创建,则在整个应用运行的过程中表面上不会报出任何错误,然而通过一个共享内存对象进行数据传输的目的将无法实现。
AIX、Solaris、HP-UX均明确指出,key文件被删除并重建后,不保证通过ftok得到的键值不变,比如AIX上ftok的man帮助信息即声明:
Attention: If the Path parameter of the ftok subroutine names a file that has been removed while keys still refer to it, the ftok subroutine returns an error. If that file is then re-created, the ftok subroutine will probably return a key different from the original one.
Linux没有提供类似的明确声明,但我们可以通过下面的简单例程test01.c,得到相同的印证:
#include <stdio.h>
#include <sys/ipc.h>
void main(int argc, char* argv[])
{
if (argc !=2 ) {
printf("Usage: %s KeyFile\n e.g. %s /tmp/mykeyfile\n", argv[0], argv[0]);
return;
}
printf("Key generated by ftok: 0x%x\n", ftok(argv[1], 1));
}
|
将上述例程在Red Hat Enterprise Linux AS release 4平台上编程成可执行程序test01,并且通过touch命令在 /tmp目录下创建一个新文件mykeyfile,然后为该文件生成键值:
# touch /tmp/mykeyfile
# ./test01 /tmp/mykeyfile
Key generated by ftok: 0x101000b
|
然后,将/tmp/mykeyfile删除,并且通过vi命令重新创建该文件,再次生成键值:
# ./test01 /tmp/mykeyfile
Key generated by ftok: 0x1010017
|
我们可以看到,虽然文件名称都是 /tmp/mykeyfile,并未改变,但由于中间发生了文件删除并重新创建的操作,前后两次所得到的键值已经不再相同。
避免此类问题最根本的方法,就是采取措施保证pathname所指定的文件(或目录)在共享内存的使用期间不被删除,不要使用有可能被删除的文件;或者干脆直接指定键值,而不借助ftok来获取键值。
我在CENTOS5.2下实测结果:如果用同样的方式创建mykeyfile,得到的键值不变。
如果创建方式不同则键值不同。
两次touch.
两次vi.
一次touch 一次vi.