文件锁以及多路复用方式解决多个用户对一个文件的操作

来源:互联网 发布:手机最新wpa2破解软件 编辑:程序博客网 时间:2024/06/06 09:43

文件锁用于多个用户共同使用或操作同一个文件。有读锁的时候可以再加读锁,不能再加写锁。有写锁的时候,不能加任何锁,加读锁时,该描述符必须是读打开,加写锁时,该描述符必须是写打开,且只在进程间有用。  

 

使用flock(锁定文件或解除锁定)函数

头文件 #include<sys/file.h>
定义函数 int flock(int fd,int operation);
函数说明 flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。
参数
operation有下列四种情况:
LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。
LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
LOCK_UN 解除文件锁定状态。
LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SHLOCK_EXOR(|)组合。
单一文件无法同时建立共享锁定和互斥锁定,而当使用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_SETLKWF_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;  

  

}  

在两个终端中测试:

两个终端可以同时加上读锁。

有一个终端加上读锁,则必须等读锁释放才能加写锁。

有一个终端加写锁必须释放才能加别的锁。 

二、多路复用:selectpoll

#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;  

    }  

    //选出最大的fdselect()函数用的  

    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 0
原创粉丝点击