问题:
- 多进程/线程写同一文件时,此时需要加锁,但如果还涉及更名、删除此文件的操作,会不会有异常出现呢?程序会不会因此挂掉呢?
测试:(下面按照几种不同情况进行测试)
- 更名操作 ==》两个进程都打开文件之后,一个锁住(IOTest),一个等待锁(IOTest2),此时修改文件iotest.log的名字
修改文件名之前的状态
修改文件名之后状态(两个进程都可以成功写入)
- 更名操作 ==》IOTest进程打开文件并锁住文件,IOTest2不打开文件,此时修改文件iotest.log的名字
修改文件名之前的状态
修改文件名之后状态(IOTest进程数据写入至修改文件名后的文件,IOTest2进程数据写入新创建iotest.log文件)
- 删除操作 ==》两个进程都打开文件,一个进程锁住(IOTest),一个进程等待锁(IOTest2),此时删除文件
删除文件后,进程分别处于锁和等待锁状态
删除文件后继续操作,未发生报错,程序正常锁、解锁、关闭描述符等
- 删除操作 ==》单独起一个进程,strace跟踪情况
正常运行
结论:
- 只要是文件被进程打开了,那之后无论是文件更名,还是进程加锁、解锁,进程最终指向的都是此文件,内容也一定是写入此文件,并写入成功的
- 如果文件被进程打开之后,后来又被删除掉了,那无论进程加锁、解锁、还是写数据,都不会报错,当然虽然不报错,但写入的数据写到哪里就不得而知了
测试代码:
/****** IOTest ******/
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
#include <stdio.h>
#include <sys/time.h>
#define IOTEST_DIR "/tmp/"
#define IOTEST_WSTR "this is iotest\n"
static void iotest_print(char *pstr)
{
char c[8];
printf("%s\n", pstr);
fgets(c, 8, stdin);
return;
}
int main()
{
int r;
FILE *fp = NULL;
char fpath[256] = {0};
char *pstr;
snprintf(fpath, sizeof(fpath), "%siotest.log", IOTEST_DIR);
iotest_print("即将打开/创建文件, 继续请按任意键...");
fp = fopen(fpath, "at+");
if (fp == NULL)
{
printf("fopen failed: %s\n", strerror(errno));
return -1;
}
re_lock:
iotest_print("即将锁住此文件, 继续请按任意键...");
r = flock(fileno(fp), LOCK_EX);
if (r)
{
if (errno == EINTR)
{
goto re_lock;
}
fclose(fp);
fp = NULL;
return -1;
}
iotest_print("即将写入数据至缓冲区, 继续请按任意键...");
fwrite(IOTEST_WSTR, sizeof(IOTEST_WSTR), 1, fp);
iotest_print("即将把数据从缓冲区刷入磁盘, 继续请按任意键...");
fflush(fp);
re_input:
iotest_print("即将解锁, 继续请按任意键...");
flock(fileno(fp), LOCK_UN);
iotest_print("解锁完成, 即将关闭描述符, 继续请按任意键...");
fclose(fp);
printf("文件描述符已关闭, 操作完成, 正在退出...\n");
return 0;
}
/****** IOTest2 ******/
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
#include <stdio.h>
#include <sys/time.h>
#define IOTEST2_DIR "/tmp/"
#define IOTEST2_WSTR "this is iotest2\n"
static void iotest2_print(char *pstr)
{
char c[8];
printf("%s\n", pstr);
fgets(c, 8, stdin);
return;
}
int main()
{
int r;
FILE *fp = NULL;
char fpath[256] = {0};
char *pstr;
snprintf(fpath, sizeof(fpath), "%siotest.log", IOTEST2_DIR);
iotest2_print("即将打开/创建文件, 继续请按任意键...");
fp = fopen(fpath, "at+");
if (fp == NULL)
{
printf("fopen failed: %s\n", strerror(errno));
return -1;
}
re_lock:
iotest2_print("即将锁住此文件, 继续请按任意键...");
r = flock(fileno(fp), LOCK_EX);
if (r)
{
if (errno == EINTR)
{
goto re_lock;
}
fclose(fp);
fp = NULL;
return -1;
}
iotest2_print("即将写入数据至缓冲区, 继续请按任意键...");
fwrite(IOTEST2_WSTR, sizeof(IOTEST2_WSTR), 1, fp);
iotest2_print("即将把数据从缓冲区刷入磁盘, 继续请按任意键...");
fflush(fp);
re_input:
iotest2_print("即将解锁, 继续请按任意键...");
flock(fileno(fp), LOCK_UN);
iotest2_print("解锁完成, 即将关闭描述符, 继续请按任意键...");
fclose(fp);
printf("文件描述符已关闭, 操作完成, 正在退出...\n");
return 0;
}