文件锁和IO多路复用
作者:互联网
文件锁和IO多路复用
一直没用过fcntl/select/poll/epoll,今天便花了点时间看看,主要简短的记录几个例子。
1.fcntl
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
fd:文件描述符
lock:结构为flock,设置记录锁的具体状态
struct flock
{
short l_type;//F_RDLCK/F_WRLCK/F_UNLCK 读取锁/写入锁/解锁
off_t l_start;//类似于fseek里面的相对偏移量
short l_whence;//类似于fseek里面的偏移起点
off_t l_len;//加锁区域的长度
pid_t l_pid;//给当前区域加锁的进程ID
};
F_DUPFD:复制文件描述符
F_GETFD:获得fd的close-on-exec标志,若标志未设置,则文件经过exec()之后,仍然保持打开状态
F_SETFD:设置close-on-exec标志,由参数arg的FD_CLOEXEC位决定
F_GETFL:得到open设置的标志
F_SETFL:改变open设置的标志
F_GETLK:应该是获取lock状态的
F_SETLK:设置lock状态
F_SETLKW:阻塞设置lock状态
成功,返回0,-1则为出错
lock_set.c
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
int lock_set(int fd,int type)
{
struct flock old_lock,lock;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_type = type;
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;
if((fcntl(fd,F_SETLKW,&lock))<0)
{
printf("lock failed:type = %d\n",lock.l_type);
return 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("release lock by %d\n",getpid());
}
break;
}
return 0;
}
write.c
#include<sys/file.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
int fd;
fd = open("hello",O_RDWR|O_CREAT,0644);
if(fd<0)
{
printf("open file error\n");
exit(1);
}
lock_set(fd,F_WRLCK);
getchar();
lock_set(fd,F_UNLCK);
getchar();
close(fd);
exit(0);
}
运行两个终端,就可以发现
第二个终端想加写锁,就会被阻塞住。
等第一个终端解锁以后,第二个终端才会加锁成功。
稍微改改上面的程序,编程设置加读取锁,就能发现写锁在的时候,加读取锁被阻塞。
只是很奇怪,为什么只能阻塞C程序打开文件这样的。我用vim还是能正常保存修改。
select
3.poll
#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<errno.h>
#include<poll.h>
#define MAX_BUFFER_SIZE 1024
#define IN_FILES 3
#define TIME_DELAY 60000
#define MAX(a,b) ((a>b)?(a):(b))
int main()
{
struct pollfd fds[IN_FILES];
char buf[MAX_BUFFER_SIZE];
int i,res,real_read,maxfd;
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<IN_FILES;i++)
{
fds[i].events = POLLIN;
}
while(fds[0].events||fds[1].events||fds[2].events)
{
if(poll(fds,IN_FILES,0)<0)
{
printf("poll error or time out\n");
return 1;
}
for(i=0;i<IN_FILES;i++)
{
if(fds[i].revents)
{
memset(buf,0,MAX_BUFFER_SIZE);
real_read = read(fds[i].fd,buf,MAX_BUFFER_SIZE);
if(real_read<0)
{
if(errno!=EAGAIN)
{
return 1;
}
}
else if(!real_read)
{
close(fds[i].fd);
fds[i].events = 0;
}
else
{
if(i==0)
{
if((buf[0]=='q')||(buf[0]=='Q'))
{
return 1;
}
}
else
{
buf[real_read] = '\0';
printf("%s",buf);
}
}
}
}
}
}
这个主要是
利用管道把2个终端的输出传到了第执行主程序的终端。
首先在第一个终端创建管道。
然后在第二、第三个终端分别重定向输出。
然后第一个终端执行主程序,在其余两个终端进行输入即可。
也就是在其他终端的输入,会输出到终端1的控制台。
4.epoll
参考以下博客就好了
https://blog.csdn.net/weixin_34111790/article/details/89601839
https://blog.csdn.net/wteruiycbqqvwt/article/details/90299610
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
printf("first\n");
int epfd = epoll_create(1);
printf("second\n");
int fd;
fd = open("hello",O_RDWR|O_CREAT,0644);
if(fd<0)
{
printf("open file error\n");
exit(1);
}
struct epoll_event event1,event2;
event1.events = EPOLLOUT|EPOLLIN;
event1.data.fd = fd;
printf("before Error no.%d:\n", errno);
int result = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event1);
printf("result = %d\n",result);
printf("after Error no.%d: %s\n", errno, strerror(errno));
while(1)
{
printf("before wait\n");
int num = epoll_wait(epfd,&event2,1,-1);
printf("num = %d\n",num);
printf("fd = %d\n",event2.data.fd);
if((event2.events&EPOLLOUT)||(event2.events&EPOLLIN))
{
char data[] = "this is my add";
fwrite(data,1,strlen(data),fd);
break;
}
}
printf("finish\n");
close(fd);
close(epfd);
}
本来想着利用读写锁阻塞文件,等释放后再用epoll_wait来写文件的。
查了查,epoll不支持对普通文件的读写。
好吧,那就这样了,只是稍微熟悉一下用法即可。
标签:文件,多路复用,int,lock,fd,终端,IO,include,type 来源: https://www.cnblogs.com/dayq/p/16342725.html