Linux思考题

如果多个用户对一个文件进行操作的时候,如何解决,考虑用文件锁的形式和多路复用的形式?
查阅各个网站得到下面的总结
①文件锁用于多个用户共同使用或操作同一个文件。有读锁的时候可以再加读锁,不能再加写锁。有写锁的时候,不能加任何锁,加读锁时,该描述符必须是读打开,加写锁时,该描述符必须是写打开,且只在进程间有用。

使用flock(锁定文件或解除锁定)函数
头文件 #include<sys/file.h>
定义函数 int flock(int fd,int operation);
函数说明 flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。
参数
operation有下列四种情况:
LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。
LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
LOCK_UN 解除文件锁定状态。
LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。
单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。
返回值 返回0表示成功,若有错误则返回-1,错误代码存于errno。
上锁方法
int lock_set(int fd,int type){
struct flock lock;

lock.l_type=type;
lock.l_start=0;
lock.l_whence=SEEK_SET;
lock.l_len = 0;
lock.l_pid=-1;

fcntl(fd,F_GETLK,&lock);
if(lock.l_type!=F_UNLCK){
if(lock.l_type == F_RDLCK)
printf("Read lock already set by %d!\n",lock.l_pid);
else if(lock.l_type == F_WRLCK)
printf("Write lock already set by %d!\n",lock.l_pid);
}
lock.l_type = type;
//此处的F_SETLKW为F_SETLK的阻塞版本,当无法获取锁时进入睡眠等待状态
if(fcntl(fd,F_SETLKW,&lock)<0){
printf("Lock failed:type=%d!\n",lock.l_type);
exit(1);
}

switch(lock.l_type){
case F_RDLCK:
printf("read lock set by %d\n",getpid());
break;
case F_WRLCK:
printf("write lock set by %d\n",getpid());
break;
case F_UNLCK:
printf("UN lock set by %d\n",getpid());
break;
default:
break;
}
}

上写锁
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include"lock.c"

int main(){
int fd;
fd=open("readme",O_RDWR|O_CREAT,0666);
if(fd<0){
printf("Open file error\n");
exit(1);
}
lock_set(fd,F_WRLCK);
getchar();
lock_set(fd,F_UNLCK);
getchar();
return 0;

}
上读锁
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include"lock.c"

int main(){
int fd;
fd=open("readme",O_RDWR|O_CREAT,0666);
if(fd<0){
printf("Open file error\n");
exit(1);
}
lock_set(fd,F_RDLCK);
getchar();
lock_set(fd,F_UNLCK);
getchar();
return 0;

}
在两个终端中测试:
两个终端可以同时加上读锁。
有一个终端加上读锁,则必须等读锁释放才能加写锁。
有一个终端加写锁必须释放才能加别的锁。
二、多路复用:select、poll
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#define MAX(a,b) (a>b?a:b)

int main(){
int fd[3];
char buff[1024];
int res,max_fd,i,num;
fd_set insert,temp_insert;
struct timeval tv;
fd[0]=0;
if((fd[1]=open("in1",O_RDONLY|O_NONBLOCK))<0){
printf("open in1 error!\n");
return 1;
}
if((fd[2]=open("in2",O_RDONLY|O_NONBLOCK))<0){
printf("open in2 error!\n");
return 1;
}
//选出最大的fd,select()函数用的
max_fd=MAX(MAX(fd[0],fd[1]),fd[2]);
//清空fd_set
FD_ZERO(&insert);
for(i=0;i<3;i++){
FD_SET(fd[i],&insert);
}
//设置延迟
tv.tv_sec=60;
tv.tv_usec=0;

while(FD_ISSET(fd[0],&insert) || FD_ISSET(fd[1],&insert) || FD_ISSET(fd[2],&insert)){
temp_insert = insert;
//select函数会对fd_set产生修改,只保存变化的文件符,所以要用一个temp
res=select(max_fd+1,&temp_insert,NULL,NULL,&tv);
switch(res){
case -1:
printf("select error!\n");
return 1;
break;
case 0:
printf("time out\n");
return 1;
break;
default:
for(i=0;i<3;i++){
if(FD_ISSET(fd[i],&temp_insert)){
memset(buff,0,1024);
num=read(fd[i],buff,1024);
if(num<0){
return 1;
}else if(num == 0){
close(fd[i]);
FD_CLR(fd[i],&insert);
}else{
if(i == 0){
if((buff[0] == 'q') || (buff[0] == 'Q')){
return 0;
}
}
write(STDOUT_FILENO,buff,num);

}
}
}
}
}
}
poll用法与select很相似,只是在一些变量上有些不同:
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>

#define MAX_BUFFER_SIZE 1024
#define IO_IN_FILES 3
#define TIME_DELAY 60000

int main() {
struct pollfd fds[IO_IN_FILES];
char buff[MAX_BUFFER_SIZE];
int i,res,real_read;

fds[0].fd=0;
if((fds[1].fd=open("in1",O_RDONLY|O_NONBLOCK))<0) {
printf("Open in1 error!\n");
return 1;
}

if((fds[2].fd=open("in2",O_RDONLY|O_NONBLOCK))<0) {
printf("Open in2 error!\n");
return 1;
}

for(i=0;i<IO_IN_FILES;i++)
fds[i].events=POLLIN;

while(fds[0].events||fds[1].events||fds[2].events) {
res=poll(fds,IO_IN_FILES,TIME_DELAY);

switch(res) {
case -1:
printf("POLL error!\n");
return 1;
break;
case 0:
printf("Time out!\n");
return 1;
break;
default:
for(i=0;i<IO_IN_FILES;i++) {
if(fds[i].revents) {
memset(buff,0,MAX_BUFFER_SIZE);
real_read=read(fds[i].fd,buff,MAX_BUFFER_SIZE);
if(real_read<0){
printf("Read error!\n");
return 1;
} else if (real_read==0) {
close(fds[i].fd);
fds[i].events=0;
} else {
if (i==0) {
if((buff[0]=='q')||(buff[0]=='Q'))
return 0;
} else {
write(STDOUT_FILENO, buff,real_read);
// buff[real_read]='\0';
// printf("%s",buff);
}
}

}

}
}
}

return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值