文件共享

一个进程打开了两个文件
文件表条目(file-table-entry):
1.文件状态标志(file-status-flags): 读/写/追加/同步/非阻塞等;
2.当前文件偏移量
3.v节点指针
-
- int main(int argc, char *argv[])
- {
- int fd1 = open("test.txt", O_RDONLY);
- if (fd1 == -1)
- err_exit("fd1 open O_RDONLY error");
- int fd2 = open("test.txt", O_RDWR);
- if (fd2 == -1)
- err_exit("fd2 open O_RDWR error");
-
-
- char buf[BUFSIZ];
- if (read(fd1, buf, 10) == -1)
- err_exit("read fd1 error");
- cout << "fd1: " << buf << endl;
-
-
- bzero(buf, 10);
- if (read(fd2, buf, 10) == -1)
- err_exit("read fd1 error");
- cout << "fd2: " << buf << endl;
-
- lseek(fd1, 0, SEEK_SET);
- lseek(fd2, 0, SEEK_SET);
- write(fd2, "Helloworld", 10);
- bzero(buf, 10);
- if (read(fd1, buf, 10) == -1)
- err_exit("read fd1 error");
- cout << "after fd2 write: " << buf << endl;
- }
一个进程多次打开同一个文件,文件指针是互不干扰的,因为他们各自维护自己文件表(数据结构),但是如果修改了文件的内容,那么v结点信息改变,则都会受到影响。

两个独立的进程打开同一个文件
复制文件描述符

方法有三种:
1.dup
2.dup2
其中dup2相当于先close在执行dup。
- #include
- int dup(int oldfd);
- int dup2(int oldfd, int newfd);
-
- int main(int argc, char *argv[])
- {
- int fd = open("text.txt", O_WRONLY|O_TRUNC);
- if (fd == -1)
- err_exit("open O_WRONLY error");
-
-
-
- int dupfd = dup2(fd, 1);
- cout << "dupfd = " << dupfd << endl;
- }
-
-
-
- int main(int argc, char *argv[])
- {
- if (argc < 3)
- err_quit("usage: ./main file-name1 file-name2");
-
- close(STDIN_FILENO);
- open(argv[1], O_RDONLY);
- close(STDOUT_FILENO);
- open(argv[2], O_WRONLY|O_CREAT, 0666);
-
- execlp("/bin/cat", "cat", NULL);
- err_exit("execlp error");
- }
3.fcntl
- int fcntl(int fd, F_DUPFD, ... );
-
fcntl
- #include
- #include
- int fcntl(int fd, int cmd, ... );
操纵文件描述符, 改变已经打开的文件的属性
fcntl常用操作(cmd常用取值) |
F_DUPFD (long) |
复制文件描述符 |
F_GETFD (void) F_SETFD (long) |
文件描述符标志 |
F_GETFL (void) F_SETFL (long) |
文件状态标志 |
F_GETLK F_SETLK,F_SETLKW(阻塞) |
文件锁 |
-
- int main(int argc, char *argv[])
- {
- int fd = open("text.txt", O_WRONLY|O_TRUNC);
- if (fd == -1)
- err_exit("open O_WRONLY error");
-
- close(1);
-
- int dupfd = fcntl(fd, F_DUPFD, 1);
- if (dupfd < 0)
- err_exit("fcntl F_DUPFD error");
- cout << "dupfd = " << dupfd << endl;
- }
文件状态标志
F_GETFL (void)
Get the file access mode and the file status flags; arg is ignored.
F_SETFL (int)
Set the file status flags to the value specified by arg. File access mode(O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. On Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
设置文件状态的时候,注意要先使用F_GETFL获取,否则原来的状态会丢失。
-
- int main(int argc, char *argv[])
- {
- int flags = fcntl(0, F_GETFL, 0);
- if (flags == -1)
- err_exit("fcntl get error");
- flags |= O_NONBLOCK;
- if (fcntl(0, F_SETFL, flags) == -1)
- err_exit("fcntl set error");
-
- char buf[BUFSIZ];
- if (read(0, buf, sizeof(buf)) == -1)
- err_exit("read STDIN_FILENO error");
- cout << "buffer size = " << strlen(buf) << endl;
- cout << buf << endl;
- }
-
- void set_fl(int fd, int setFlag)
- {
- int flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1)
- err_exit("fcntl get flags error");
-
- flags |= setFlag;
- if (fcntl(fd, F_SETFL, flags) == -1)
- err_exit("fcntl set flags error");
- }
- void clr_fl(int fd, int clrFlag)
- {
- int flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1)
- err_exit("fcntl get flags error");
-
- flags &= ~clrFlag;
- if (fcntl(fd, F_SETFL, flags) == -1)
- err_exit("fcntl set flags error");
- }
-
-
- int main(int argc, char *argv[])
- {
- set_fl(0, O_NONBLOCK);
- clr_fl(0, O_NONBLOCK);
- char buf[BUFSIZ];
- if (read(0, buf, sizeof(buf)) == -1)
- err_exit("read STDIN_FILENO error");
- cout << "buffer size = " << strlen(buf) << endl;
- cout << buf << endl;
- }
文件锁
F_SETLK (struct flock *)
Acquire a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len fields of lock. If a conflicting lock is held by another process, this call returns -1 and sets errno to EACCES or EAGAIN.
F_SETLKW (struct flock *) 如果加锁不成功:会一直阻塞直到解锁
As for F_SETLK, but if a conflicting lock is held on the file, then wait for that lock to be released. If a signal is caught while waiting, then the call is interrupted and (after the signal handler has returned) returns immediately (with return value -1 and errno set to EINTR; see signal(7)).
F_GETLK (struct flock *)
On input to this call, lock describes a lock we would like to place on the file.
If the lock could be placed, fcntl() does not actually place it, but returns F_UNLCK in the l_type field of lock and leaves the other fields of the structure unchanged. If one or more incompatible locks would prevent this lock being placed, then fcntl() returns details about one of these locks in the l_type, l_whence, l_start, and l_len fields of lock and sets l_pid to be the PID of the process holding that lock.
-
- struct flock
- {
- ...
- short l_type;
-
- short l_whence;
-
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-
- ...
- };
注意: Specifying 0 for l_len has the special meaning: lock all bytes starting at
the location specified by l_whence and l_start through to the end of file,
no matter how large the file grows.
-
- int main(int argc, char *argv[])
- {
- int fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
- if (fd == -1)
- err_exit("open file error");
-
- struct flock lock;
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
-
-
- if (fcntl(fd, F_SETLKW, &lock) == 0)
- {
- cout << "file lock success, press any key to unlock..." << endl;
- cin.get();
-
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- if (fcntl(fd, F_SETLK, &lock) == -1)
- err_exit("file unlock error");
- else
- cout << "file unlock success" << endl;
- }
- else
- err_exit("file lock error");
- }
-
- int main(int argc, char *argv[])
- {
- int fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
- if (fd == -1)
- err_exit("open file error");
-
- struct flock lock;
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
-
- if (fcntl(fd, F_SETLK, &lock) == 0)
- {
- cout << "file lock success, press any key to unlock..." << endl;
- cin.get();
-
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- if (fcntl(fd, F_SETLK, &lock) == -1)
- err_exit("file unlock error");
- else
- cout << "file unlock success" << endl;
- }
- else
- {
- if (fcntl(fd, F_GETLK, &lock) == -1)
- err_exit("get lock error");
-
- cout << "lock process: " << lock.l_pid << endl;
- if (lock.l_type == F_WRLCK)
- cout << "type: F_WRLCK" << endl;
- else
- cout << "type: F_RDLCK" << endl;
-
- if (lock.l_whence == SEEK_SET)
- cout << "whence: SEEK_SET" << endl;
- else if (lock.l_whence == SEEK_END)
- cout << "whence: SEEK_END" << endl;
- else
- cout << "whence: SEEK_CUR" << endl;
- }
- }