数据管理三个阶段的优缺点,数据管理三个阶段的比较
文件锁
文件锁是多用户多任务操作系统的重要组成部分。程序经常需要共享数据,通常是通过文件,所以对于这些程序来说,有一种建立文件控制的方法是非常重要的。通过这种方式,可以安全地更新文件,或者当一个程序正在写入文件时,另一个程序将阻止自己尝试读取文件。
Linux有许多我们可以用于文件锁的特性。最简单的方法是以原子的方式创建一个文件锁,这样在锁被创建之后,它可以阻止任何其他事情的发生。这为程序提供了一种创建其他程序不能同时创建的单个文件的方法。
第二种方法更先进;他允许程序锁定文件的一部分进行独占访问。有两种方法可以实现这种锁定。我们将只详细讨论其中的一种,因为第二种方法非常简单,但是具有稍微不同的程序接口。
创建一个锁定文件
许多程序只需要能够为资源创建一个锁文件。其他程序可以检查以确定它们是否被允许访问这些资源。
通常,这些锁文件位于一个特殊的位置,它们的名称与被控制的资源有关。例如,当使用调制解调器时,Linux会创建一个锁文件,通常使用/usr/spool或/var/spool中的目录。
请记住,锁文件只作为一个标识符;程序需要合作才能使用它们。它们被称为顾问锁,与强制锁不同,后者的锁系统会强制锁。
为了创建带有锁标识符的文件,我们使用fcntl.h中定义的开放系统调用,并使用O_CREAT和O_EXCL标志。这将允许我们检查该文件是否已经存在,并通过单个atom操作创建该文件。
实验-创建一个锁文件。
让我们使用lock1.c程序来理解创建锁的操作:
#包括unistd.h
#包含stdlib.h
#包含stdio.h
#包含fcntl.h
#包含错误号h
int main()
{
int file _ desc;
int save _ errno
file_desc=open("/tmp/LCK.test ",O_RDWR O_CREAT O_EXCL,0444);
如果(文件desc==-1) {
save _ errno=errno
printf("打开失败,出现错误%d/n ",save _ errno);
}
否则{
printf("打开成功/n ");
}
退出(EXIT _ SUCCESS);
}
当我们第一次运行这个程序时,它的输出结果如下:
$ lock1
打开成功
但是当我们再次运行这个程序时,我们会得到以下信息:
$ lock1
打开失败,出现错误17
操作原理
程序调用open系统调用,并使用O_CREAT和O_EXCL标记创建一个名为/tmp/LCK.test的文件。当我们第一次运行这个程序时,这个文件并不存在,所以open调用是成功的。下一个程序调用失败,因为该文件已经存在。为了使这个程序再次成功运行,我们必须删除这个锁定文件。
至少在Linux系统中,错误17指的是EEXIST,这是一个用来表示文件已经存在的错误。错误号在errno.h头文件或它包含的多个文件中定义。在这种情况下,这个定义实际上位于文件/usr/include/asm/errno.h中:
#define EEXIST 17 /*文件存在*/
这是open(O_EXCL O_CREAT)失败对应的错误。
如果一个程序在运行期间只需要短时间独占一个资源,这种情况通常称为临界区。程序应该在进入临界区之前创建一个锁文件,在退出临界区时使用unlink删除锁文件。
我们可以通过编写一个示例文件并同时运行该程序的两个副本来演示程序如何使用这种锁定机制。我们将使用getpid调用,这是我们在第4章中学到的。它将返回一个进程ID,通常是每个当前正在执行的程序的唯一标签。
测试组合文件锁
1下面是我们的测试程序lock2.c的源代码:
#包括unistd.h
#包含stdlib.h
#包含stdio.h
#包含fcntl.h
#包含错误号h
const char * lock _ file="/tmp/lck . test 2 ";
int main()
{
int file _ desc;
int tries=10
while(尝试次数- ) {
file_desc=open(lock_file,O_RDWR O_CREAT O_EXCL,0444);
如果(文件desc==-1) {
printf("%d - Lock已经存在/n ",getpid());
睡眠(3);
}
否则{
2这里是临界区的开始:
printf("%d -我有独占访问权/n ",getpid());
睡眠(1);
(void)关闭(file _ desc);
(void)unlink(lock _ file);
3下面是程序的结尾:
睡眠(2);
}
}
退出(EXIT _ SUCCESS);
}
要运行这个程序,我们应该首先使用以下命令来确保锁文件不存在:
$ rm -f /tmp/LCK.test2
然后,我们使用以下命令运行程序的两个副本:
$ ./lock2。/lock2
这将在后端运行lock2的副本,并在前端运行一个副本。下面是我们得到的程序输出:
1284 -我有专属权限
1283 -锁已经存在
1283 -我有专属权限
1284 -锁已经存在
1284 -我有专属权限
1283 -锁已经存在
1283 -我有专属权限
1284 -锁已经存在
1284 -我有专属权限
1283 -锁已经存在
1283 -我有专属权限
1284 -锁已经存在
1284 -我有专属权限
1283 -锁已经存在
1283 -我有专属权限
1284 -锁已经存在
1284 -我有专属权限
1283 -锁已经存在
1283 -我有专属权限
1284 -锁已经存在
前面的例子演示了同一个程序的两个调用是如何协作的。如果我们尝试这个程序,我们在输出中看到的只是不同的进程标识符,而程序的行为是相同的。
操作原理
出于程序演示的目的,我们使用while循环让程序运行10次。然后,程序将通过创建唯一的锁文件/tmp/lck.test2来尝试访问关键资源。如果由于文件已经存在而失败,程序将等待一段时间,然后重试。如果成功,程序可以访问该资源,并在标识为临界区的部分中实现独占访问所需的处理。
因为只是演示,我们只是等了一小会儿。当程序完成对资源的访问时,程序将通过删除锁文件来释放锁。在重新获得锁之前,程序可以执行一些其他操作。锁相当于一个二进制信号量。对于“我可以使用这个资源吗?”给这个问题一个是或否的答案。我们将在第14章学习更多关于信号量的知识。
需要注意的是,这是一个合作任务,我们必须正确地编写程序才能使它工作。如果程序无法创建锁文件,它可以简单地删除该文件并重试。他可以创建锁文件,但是创建锁文件的其他程序无法知道他不再是独占资源。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。