数据管理(三)

文件锁

文件锁是多用户,多任务操作系统的重要一部分。程序经常需要共享数据,通常是通过文件,所以对于这些程序来说有一种可以建立文件控制的方法是十分重要的。这样文件就可以安全的进行更新,或者当一个程序在写入文件时,另一个程序会阻止自己试图由文件中读取。

Linux有许多我们可以用于文件锁的特性。最简单的方法就是以原子方式创建文件锁的技术,从而当创建了这个锁以后可以阻止其他任何事情的发生。这样就赋予程序一种方法,从而可以创建单一的文件并且不可以被其他程序同时创建。

第二种方法要更为高级;他允许程序加锁文件的一部分进行排他访问。有两种方法可以做到这种加锁方式。我们只会详细的讨论其中的一种,因为第二种方法很简单,只是具有一个略微不同的程序接口。

创建锁文件

许多程序只需要可以为资源创建一个锁文件。其他的程序可以进行检测以确定他们是否允许访问这些资源。

通常,这些锁文件位于一个特殊的位置,并且其名字与正在被控制的资源相关。例如,当一个调制解调器正在使用时,Linux创建一个锁文件,通常是使用/usr/spool或是/var/spool目录中的一个目录。

记住锁文件的作用只是标识符;程序需要进行合作来使用他们。他们被称之为建议锁(advisory lock),从而与强制锁相区别(mandatory lock),而后一种锁系统会强制锁的行为。

要创建一个使用锁标识符的文件,我们使用定义在fcntl.h中是的open系统调用,并且使用O_CREAT与O_EXCL标志位。这会允许我们检测这个文件是否已经存在,并且以单一原子操作的方式创建这个文件。

试验--创建一个锁文件

下面我们使用lock1.c程序来了解一下创建锁的动作:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
int main()
{
int file_desc;
int save_errno;
file_desc = open(“/tmp/LCK.test”, O_RDWR | O_CREAT | O_EXCL, 0444);
if (file_desc == -1) {
save_errno = errno;
printf(“Open failed with error %d/n”, save_errno);
}
else {
printf(“Open succeeded/n”);
}
exit(EXIT_SUCCESS);
}

当我们第一次运行这个程序时,其输出结果如下:

$ lock1
Open succeeded

但是当我们再次运行这个程序时,我们会得到下面的信息:

$ lock1
Open failed with error 17

工作原理

程序调用open系统调用,并且使用O_CREAT与O_EXCL标记来创建名为/tmp/LCK.test的文件。我们第一次运行这个程序时,文件并不存在,所以open调用是成功的。接下来的程序调用失败是因为这个文件已经存在了。要使得这个程序再次运行成功,我们必须移除这个锁文件。

至少在Linux系统中,错误17指EEXIST,是用来表明文件已经存在的一个错误。错误号定义在errno.h头文件或是更多的由其所包含的文件中。在这种情况下,这个定义实际上位于/usr/include/asm/errno.h文件中:

#define EEXIST 17 /* File exists */

这是对应于open(O_EXCL | O_CREAT)失败的错误。

如果一个程序只是其运行期间的短暂时间内需要排他的使用一个资源,通常将这种情况称之为临界部分(critical section),程序应该在进行临界区之前创建锁文件,并且在退出临界区时使用unlink来删除这个锁文件。

我们可以通过编写一个示例文件并且在同时运行这个程序的两份拷贝来演示程序如何通过组合使用这个锁机制。我们将会使用getpid调用,这个调用我们已经在第四章了解过了,他会返回一个进程标识,通常是为每一个当前正在执行的程序返回一个唯一的标号。

试验--组合文件锁

1 下面是我们的测试程序lock2.c的源代码:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
const char *lock_file = “/tmp/LCK.test2”;
int main()
{
int file_desc;
int tries = 10;
while (tries--) {
file_desc = open(lock_file, O_RDWR | O_CREAT | O_EXCL, 0444);
if (file_desc == -1) {
printf(“%d - Lock already present/n”, getpid());
sleep(3);
}
else {

2 下面是临界区开始的部分:

printf(“%d - I have exclusive access/n”, getpid());
sleep(1);
(void)close(file_desc);
(void)unlink(lock_file);

3 下面是程序的结束部分:

sleep(2);
}
}
exit(EXIT_SUCCESS);
}

要运行这个程序,我们应首先使用下面的命令来保证锁文件不存在:

$ rm -f /tmp/LCK.test2

然后我们用下面的命令来运行程序的两份拷贝:

$ ./lock2 & ./lock2

这会在后端运行lock2的一份拷贝并且在前端运行一份拷贝。下面是我们得到的程序输出:

1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present
1284 - I have exclusive access
1283 - Lock already present
1283 - I have exclusive access
1284 - Lock already present

前面的例子演示了同一个程序的两次调用是如何进行合作的。如果我们尝试这个程序,我们在输出中所看到的只是不同的进程标识符,而程序的行为是相同的。

工作原理

为了程序演示的目的,我们使用一个while循环使得程序运行10次。然后程序会通过创建一个唯一的锁文件/tmp/LCK.test2来尝试访问临界资源。如果因为文件已存在而失败,程序会等待一段时间然后再次尝试。如果成功,程序可以访问这个资源,并且在标识为临界区的部分实现排他访问所需要的处理。

因为这只是一个演示,我们只是等待了一小段时间。当程序结束资源的访问时,程序会通过删除锁文件来释放锁。程序可以在重新获得锁之前执行一些其他的操作。锁的作用相当于一个二进制信号量,对于"我可以使用这个资源吗?"的问题给出是或否的回答。我们将会在第14章了解更多有关信号量的内容。

需要注意的很重要的一点就是这是一个合作的任务,我们必须正确的编写程序从而使其工作。如果一个程序创建锁文件失败,他可以简单的删除这个文件并且再次尝试。他也许会创建锁文件,但是创建了锁文件的其他们程序并没有办法知道他已经不再是排他的使用资源了。
实验 数据管理操作 一、实验目的 1.熟悉大型数据库实验环境,以MS SQL SERVER为例; 2.掌握DDL语句,使用DDL语句完成数据表的创建; 3.掌握DML语句,使用DML语句完成数据的插入、修改和删除; 4.掌握MS SQL SERVER的备份和还原; 5.掌握MS SQL SERVER的权限分配。 二、实验内容 (1)用DDL(数据定义语句中的Create database)创建一个新数据库FlightDB,数据库文件的设置都可以使用默认值。 (2)用DDL(数据定义语句中的Create Table)创建张表 1.航班表(hbb)包括如下字段: 航班号(hbh):字符型,6位定长,主码,以CZ、CA、FM开头 始发地(sfd):字符型,可变长统一编码字符型20位长,非空 目的地(mdd):字符型,可变长统一编码字符型20位长,非空 原价(YJ):整型,非空,必须>=0 2.乘客表(Ckb)包括如下字段: 身份证号(sfzh):字符型,20位变长字符串,主码 姓名(xm):可变长统一编码字符型,10位长 3.售票表(spb)包括如下字段: 航班号(hbh):主码 身份证号(sfzh):主码 起飞日期(qfrq):日期时间型,非空 售票日期(sprq):日期时间型,非空,默认值为当前时间 实价(sj):整型,非空 其中:航班号为引用航班表的外码,身份证号为引用乘客表的外码。 (3)用DML(数据操纵语句中的Insert)在hbb表中插入如下数据 CZ1301,北京,上海,1200 CZ1209,南京,昆明,1300 CZ1502,上海,北京,1200 CA1130,成都,北京,1800 CA1230,拉萨,广州,1500 CA1401,广州,南京,1600 (4)对数据库进行一次完整备份,备份名为BackupFull (5)用DML(数据操纵语句中的Insert)在乘客表和售票表中插入如下数据 代码 乘客 91201 王曼 91202 张飞 91203 刘羽蕴 91204 王若雨 91205 张蕊 航班号 乘客 起飞 售票 实价 CZ1301 91201 2001-12-20 2001-11-20 900 CZ1209 91202 2001-12-20 2001-11-20 800 CZ1502 91201 2002-5-8 2002-5-2 1000 CA1230 91201 2001-12-5 2001-12-4 1100 CA1401 91202 2002-4-5 2002-4-4 1200 CZ1301 91203 2001-12-20 2001-11-20 900 CZ1209 91204 2001-12-20 2001-11-20 800 CZ1502 91205 2002-5-8 2002-5-2 1000 (6)对数据库进行一次差异备份,备份名为BackupAdd1 (7)用DML(数据操纵语句中的Update)将所有目的地是北京的航班的原价提高10% (8)用DML(数据操纵语句中的Delete)将“张飞”乘客删除,注意同时删除售票记录和乘客基本信息。 (9)尝试使用MS SQL Server的还原功能,还原到上一次差异备份的BackupAdd1处。 (10)在SQL Server中创建一个用户FlightUser,设置FlightUser用户对张表都有查询权,但是该用户不能对乘客表和航班表进行增加、删除和修改记录,该用户对售票表能增加、删除和修改记录。然后用FlightUser登陆SQL Server,对如上权限设置进行验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值