【C/C++业务】多进程同时读写同一个文件

文件锁

#include <sys/file.h>
int flock(int fd, int operation);

参数说明:

  • LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。
  • LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
  • LOCK_UN 解除文件锁定状态。
  • LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。
    单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。

返回值说明:

返回0表示成功,若有错误则返回-1,错误代码存于errno。

lock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。

使用方式:

  1. flock只要在打开文件后,需要对文件读写之前flock一下就可以了,用完之后再flock一下,前面加锁,后面解锁。
  2. 进程使用flock尝试锁文件时,如果文件已经被其他进程锁住,进程会被阻塞直到锁被释放掉,或者在调用flock的时候,采用LOCK_NB参数,在尝试锁住该文件的时候,发现已经被其他服务锁住,会返回错误。
  3. 可调用LOCK_UN参数来释放文件锁,也可以通过关闭fd的方式来释放文件锁(flock的第一个参数是fd),意味着flock会随着进程的关闭而被自动释放掉

测试

测试用例1

进程A:打开要操作的文件,进行加锁,在文件中写入数据,等待键盘输入字符(此时该A进程处于等待状态,立刻运行B进程),键盘输入字符后,发现加锁文件中出现text字符串

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/file.h>
static const char jsonfile[] = "new.json";
int main()
{
   FILE *fp;
  char buf[1024] = {0};
  char text[] = "this is write test=========\n";
  if ((fp = fopen((jsonfile), "aw+")) == NULL)
    return 0;

  if (0 == flock(fileno(fp), LOCK_EX))
  {
    printf("lock...\n");
    fseek(fp, 0, SEEK_END);
    fwrite(text, strlen(text), 1, fp);

    getchar();
    fclose(fp);
    flock(fileno(fp), LOCK_UN);
  }
  else
  {
    printf("lock failed\n");
  }
  return 0;
}

进程B:打开要操作的文件,进行加锁并设置立即返回参数,如果返回值是-1,说明文件已被其他进程占用,然后进行持续加锁,直到成功加锁(此时刻是由于A进程在键盘中输入了字符,释放了锁)睡眠2s后退出加锁持续,对文件进行数据追加写入操作,发现在A进程中的text字段后面出现了该B进程写入的数据,即可说明文件锁生效,能成功保护文件被两个进程同时读写操作

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

static const char jsonfile[] = "new.json";

int main()
{
   char texts[] = "-----------this is read test\n";
   FILE *fp;
   if ((fp = fopen(jsonfile, "aw+")) == 0)
      printf("can't open file!\n");
   else
   {
      printf("open file success!\n");//LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程
      int i = flock(fileno(fp), LOCK_SH | LOCK_NB); // 加锁以判断文件是否已经被加锁了,单一文件无法同时建立共享锁定和互斥锁定
      printf("%d\n", i);                          //-1表示文件被其他进程加锁,0表示文件被该进程加锁
      if (i == -1)
      {
         printf("lock by others ...\n");
         while (1)
         {
            i = flock(fileno(fp), LOCK_SH | LOCK_NB);
            if (i == 0)
            {
               sleep(2);
               printf("lock file success!!!!!!!!!!!\n");
               break;
            }
         }
      }
      flock(fileno(fp), LOCK_UN);
      fwrite(texts, strlen(texts), 1, fp);
   }

   fclose(fp);
   return 0;
}

被两个进程同时操作的new.json数据文件内容如下:

this is write test=========
-----------this is read test

第二行数据在第一行数据出现2S后才出现

结果说明:验证了flock函数在多进程操作同一个文件时对文件的保护作用

测试用例2

多进程同时操作同一个文件无延时循环读写测试

进程A:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/file.h>
static const char jsonfile[] = "new.json";

int main()
{
  char text[] = "this is write test=========\n";
  while (1)
  {
    FILE *fp;
    if ((fp = fopen((jsonfile), "aw+")) == NULL)
      return 0;
    if (0 == flock(fileno(fp), LOCK_EX))
    {
      printf("lock...\n");
      fseek(fp, 0, SEEK_END);
      fwrite(text, strlen(text), 1, fp);

      //getchar();
      fclose(fp);
      flock(fileno(fp), LOCK_UN);
    }
    else
    {
      printf("lock failed\n");
    }
  }
  //usleep(500);
  return 0;
}

进程B:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/file.h>
static const char jsonfile[] = "new.json";

int main()
{
  char text[] = "-----------this is read test\n";
  while (1)
  {
    FILE *fp;
    if ((fp = fopen((jsonfile), "aw+")) == NULL)
      return 0;
    if (0 == flock(fileno(fp), LOCK_EX))
    {
      printf("lock...\n");
      fseek(fp, 0, SEEK_END);
      fwrite(text, strlen(text), 1, fp);

      //getchar();
      fclose(fp);
      flock(fileno(fp), LOCK_UN);
    }
    else
    {
      printf("lock failed\n");
    }
  }
  //usleep(500);
  return 0;
}

经过测试两个进程在一个文件中连续不断写入数据,写入数据到该文件达到100M后停止写入,然后分析文件中的数据

分析写入数据正确性的程序:

#include <stdio.h>
#include <string.h>

static const char jsonfile[] = "/home/nfs/new.json";
char texts[] = "this is write test=========";
char text[] = "-----------this is read test";
int main()
{
  char buff[1024] = {0};
  int bufflinenum = 0, num = 0;
  FILE *fp;
  if ((fp = fopen(jsonfile, "r+")) == 0)
    printf("can't open file!\n");
  while (!feof(fp))
  {
    if (fgets(buff, sizeof(buff), fp) != NULL)
    {
      bufflinenum++;
      if((strncmp(buff, text, strlen(buff)-1) != 0 ) && strncmp(buff, texts,strlen(buff)-1) != 0 )
      {
         num++;
         printf("出错行内容:\n%s", buff);
      }
      else
      {
        //printf("%s", buff);
      }
      
    }
  }
  printf("文件总行数:%d\n出错行数:%d\n", bufflinenum, num);

  return 0;
}

分析结果:
在这里插入图片描述

相关推荐

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

徐步小兵

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值