Menu
Woocommerce Menu

使用文件进行进程间通信应该是最先学会的一种IPC方式3522vip靠谱吗:,从使用的方式和效果来看各个函数的区别

0 Comment

前言

运用文件进行进度间通讯应该是首先学会的一种IPC形式。任何编程语言中,文件IO都以很主要的文化,所以接纳文件实行进程间通讯就成了很当然被学会的一种花招。思考到系统对文件本身存在缓存机制,使用文件进行IPC的频率在好几多读少写的图景下并不放下。可是我们就像日常忘记IPC的体制可以回顾“文件”这一选项。

大家率先引进文件实行IPC,试图先选拔文件进行通讯引进三个竞争条件的概念,然后利用文件锁解决那些难题,进而先从文件的角度来一概而论的看一下连续相关IPC机制的一体化要消除的标题。阅读本文能够帮您解决以下难题:

  1. 什么样是角逐条件(racing)?。
  2. flock和lockf有哪些分别?
  3. flockfile函数和flock与lockf有怎么着差异?
  4. 什么样行职分令查看文件锁?

linux中fcntl()、lockf、flock的区别

fcntl()、lockf、flock的区别
——lvyilong316

那八个函数的功效都以给文件加锁,那它们有如何分别呢?首先flock和fcntl是系统调用,而lockf是库函数。lockf实际上是fcntl的卷入,所以lockf和fcntl的底层完结是千篇一律的,对文本加锁的作用也是如同一口的。前面解析分裂点时大许多情状是将fcntl和lockf放在一块儿的。上面首先看各样函数的施用,从利用的主意和效劳来看种种函数的分别。

竞争法规(racing)

我们的率先个例子是八个进度写文件的事例,就算还未遂通讯,不过这正如方便的说美赞臣(MeadjohnsonState of Qatar个通信时常常现身的情状:角逐原则。假设大家要并发九十六个经过,这个进程约定好一个文件,这一个文件伊始值内容写0,每多个历程都要展开那些文件读出脚下的数字,加一之后将结果写回去。在能够状态下,那个文件最终写的数字应该是100,因为有九贰10个经过张开、读数、加1、写回,自然是有微微个经过最后文件中的数字结果就相应是有一点点。不过实际上其实否则,能够看一下以此例子:

[zorro@zorrozou-pc0 process]$ cat racing.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/file.h>
#include <wait.h>

#define COUNT 100
#define NUM 64
#define FILEPATH "/tmp/count"

int do_child(const char *path)
{
    /* 这个函数是每个子进程要做的事情
    每个子进程都会按照这个步骤进行操作:
    1. 打开FILEPATH路径的文件
    2. 读出文件中的当前数字
    3. 将字符串转成整数
    4. 整数自增加1
    5. 将证书转成字符串
    6. lseek调整文件当前的偏移量到文件头
    7. 将字符串写会文件
    当多个进程同时执行这个过程的时候,就会出现racing:竞争条件,
    多个进程可能同时从文件独到同一个数字,并且分别对同一个数字加1并写回,
    导致多次写回的结果并不是我们最终想要的累积结果。 */
    int fd;
    int ret, count;
    char buf[NUM];
    fd = open(path, O_RDWR);
    if (fd < 0) {
        perror("open()");
        exit(1);
    }
    /*  */
    ret = read(fd, buf, NUM);
    if (ret < 0) {
        perror("read()");
        exit(1);
    }
    buf[ret] = '\0';
    count = atoi(buf);
    ++count;
    sprintf(buf, "%d", count);
    lseek(fd, 0, SEEK_SET);
    ret = write(fd, buf, strlen(buf));
    /*  */
    close(fd);
    exit(0);
}

int main()
{
    pid_t pid;
    int count;

    for (count=0;count<COUNT;count++) {
        pid = fork();
        if (pid < 0) {
            perror("fork()");
            exit(1);
        }

        if (pid == 0) {
            do_child(FILEPATH);
        }
    }

    for (count=0;count<COUNT;count++) {
        wait(NULL);
    }
}

其一顺序做后实行的法力如下:

[zorro@zorrozou-pc0 process]$ make racing
cc     racing.c   -o racing
[zorro@zorrozou-pc0 process]$ echo 0 > /tmp/count
[zorro@zorrozou-pc0 process]$ ./racing 
[zorro@zorrozou-pc0 process]$ cat /tmp/count 
71[zorro@zorrozou-pc0 process]$ 
[zorro@zorrozou-pc0 process]$ echo 0 > /tmp/count
[zorro@zorrozou-pc0 process]$ ./racing 
[zorro@zorrozou-pc0 process]$ cat /tmp/count 
61[zorro@zorrozou-pc0 process]$ 
[zorro@zorrozou-pc0 process]$ echo 0 > /tmp/count
[zorro@zorrozou-pc0 process]$ ./racing 
[zorro@zorrozou-pc0 process]$ cat /tmp/count 
64[zorro@zorrozou-pc0 process]$

咱俩进行了二遍那几个顺序,每趟结果都不太相符,第叁次是71,第一遍是61,第二回是64,全都未有拿走预期结果,那就是竞争准绳(racingState of Qatar引进的标题。留意深入分析那些进度大家能够发现那些角逐原则是如何产生的:

最开始文件内容是0,假诺那时候还要开拓了3个过程,那么他们分别读文件的时候,那几个进程是唯恐出现的,于是每种进程读到的数组大概都是0,因为她俩都在别的进度没写入1事情未发生前就开头读了文件。于是多少个进程都以给0加1,然后写了个1回去文件。其余进度就那样类推,每一趟玖15个进程的实行各样或许分歧,于是结果是历次获得的值都恐怕不太相像,可是不容置疑都容易位面积生产能力生的莫过于进程个数。于是我们把这种多少个实行进程(如进度或线程)中寻访同叁个分享资源,而那几个分享能源又有独力难持被多个试行进程存取的的顺序片段,叫做临界区代码。

那就是说该怎么样减轻那个racing的主题材料吧?对于那个事例来讲,可以用文件锁的法门解决这几个难题。正是说,对临界区代码实行加锁,来搞定角逐准则的主题材料。哪段是临界区代码?在此个事例中,两端/
/之间的一些正是临界区代码。一个不易的例证是:

...
    ret = flock(fd, LOCK_EX);
    if (ret == -1) {
        perror("flock()");
        exit(1);
    }

    ret = read(fd, buf, NUM);
    if (ret < 0) {
        perror("read()");
        exit(1);
    }
    buf[ret] = '\0';
    count = atoi(buf);
    ++count;
    sprintf(buf, "%d", count);
    lseek(fd, 0, SEEK_SET);
    ret = write(fd, buf, strlen(buf));
    ret = flock(fd, LOCK_UN);
    if (ret == -1) {
        perror("flock()");
        exit(1);
    }
...

我们将临界区一些代码前后都施用了flock的互斥锁,幸免了临界区的racing。那么些例子尽管并从未真的到达让七个进度经过文件进行通信,解决某种共同工作难题的目的,然而足以表现出进度间通讯机制的一对难点了。当提到到数量在三个经过间进行分享的时候,仅仅只兑现多少通讯或分享机制自己是相当不够的,还亟需得以完成相关的协作或异步机制来支配多个经过,到达保证临界区或别的让进程能够拍卖一同或异步事件的技术。大家得以感觉文件锁是足以兑现如此一种多进程的和睦联合技巧的机制,而除了那个之外文件锁以外,还会有任何编写制定能够直达近似大概分歧的效果,大家会在下文中继续详细分解。

重复,大家并不对flock这些办法自身进行功用性讲授。这种功效性批注大家能够超级轻松的在网络可能通过其他书籍得到相关内容。本文尤其尊重的是Linux景况提供了略略种文件锁以至他们的分别是什么样?

1.flock

l函数原型

#include<sys/file.h>

intflock(intfd,intoperationState of Qatar;//Applyorremoveanadvisorylockontheopenfilespecifiedbyfd,只是提出性锁

里头fd是系统调用open重临的文件描述符,operation的选项有:

LOCK_SH:共享锁

LOCK_EX:排他锁或许独自据有锁

LOCK_UN:解锁。

LOCK_NB:非窒碍(与上述三种操作一齐行使)

至于flock函数,首先要明了flock函数只好对总体文件上锁,而不能够对文件的某一片段上锁,那是于fcntl/lockf的第三个根本差异,后面一个能够对文件的某些区域上锁。其次,flock只好发出劝告性锁。大家精通,linux存在勒迫锁(mandatorylock)和劝告锁(advisorylock)。所谓强制锁,比较好精晓,正是您家大门上的那把锁,最要命的是唯有一把钥匙,独有一个历程能够操作。所谓劝告锁,本质是一种左券,你拜访文件前,先反省锁,那个时候锁才其效用,借使您不那么kind,不管三七五十九,就要读写,那么劝告锁未有其余的效应。而服从公约,读写前先检查锁的那多少个经过,叫做同盟进度。再一次,flock和fcntl/lockf的差别重要在fork和dup。

(1卡塔尔(قطر‎flock创设的锁是和文件打开表项(structfile)相关联的,实际不是fd。那就象征复制文件fd(通过fork大概dup)后,那么通过那五个fd都得以操作那把锁(比方通过三个fd加锁,通过另一个fd可以释放锁),也正是说子进度继续父进度的锁。不过上锁进度中关闭内部叁个fd,锁并不会自由(因为file构造并从未自由),唯有关门全体复制出的fd,锁才会释放。测量检验程序入程序一。

l程序一

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main (int argc, char ** argv)
{
int ret;
int fd1 = open("./tmp.txt",O_RDWR);
int fd2 = dup(fd1);
printf("fd1: %d, fd2: %d\n", fd1, fd2);
ret = flock(fd1,LOCK_EX);
printf("get lock1, ret: %d\n", ret);
ret = flock(fd2,LOCK_EX);
printf("get lock2, ret: %d\n", ret);
return 0;
}

3522vip靠谱吗 1

运作结果如图,对fd1上锁,并不影响程序通过fd2上锁。对于父亲和儿子进程,参考程序二。

l程序二

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main (int argc, char ** argv)
{
int ret;
int pid;
int fd = open("./tmp.txt",O_RDWR);
if ((pid = fork()) == 0){
ret = flock(fd,LOCK_EX);
printf("chile get lock, fd: %d, ret: %d\n",fd, ret);
sleep(10);
printf("chile exit\n");
exit(0);
}
ret = flock(fd,LOCK_EX);
printf("parent get lock, fd: %d, ret: %d\n", fd, ret);
printf("parent exit\n");
return 0;
}

3522vip靠谱吗 2

运作结果如图,子进度具备锁,并不影响父进度经过一样的fd获取锁,反之亦然。

(2卡塔尔(قطر‎使用open若干回展开同三个文件,获得的三个fd是单身的(因为后面部分对应八个file对象),通过中间四个加锁,通过另贰个不只怕解锁,况且在前贰个解锁前也心余力绌上锁。测量检验程序如程序三:

l程序三

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main (int argc, char ** argv)
{
int ret;
int fd1 = open("./tmp.txt",O_RDWR);
int fd2 = open("./tmp.txt",O_RDWR);
printf("fd1: %d, fd2: %d\n", fd1, fd2);
ret = flock(fd1,LOCK_EX);
printf("get lock1, ret: %d\n", ret);
ret = flock(fd2,LOCK_EX);
printf("get lock2, ret: %d\n", ret);
return 0;
}

3522vip靠谱吗 3

结果如图,通过fd1获取锁后,不能够再通过fd2获取锁。

(3卡塔尔国使用exec后,文件锁的景色不改变。

(4卡塔尔国flock不能够再NFS文件系统上应用,假诺要在NFS使用文件锁,请使用fcntl。

(5卡塔尔(قطر‎flock锁可递归,即经过dup可能恐怕fork产生的七个fd,都足以加锁而不会发生死锁。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图