fcntl可实现对指定文件描述符的各种操作,其函数原型如下:
int fcntl(int fd, int cmd, ... /* arg */ );
其中,操作类型由cmd决定。cmd可取如下值:
- F_DUPFD:复制文件描述符
- F_DUPFD_CLOEXEC:复制文件描述符,新文件描述符被设置了close-on-exec
- F_GETFD:读取文件描述标识
- F_SETFD:设置文件描述标识
- F_GETFL:读取文件状态标识
- F_SETFL:设置文件状态标识
- F_GETLK:如果已经被加锁,返回该锁的数据结构。如果没有被加锁,将l_type设置为F_UNLCK
- F_SETLK:给文件加上进程锁
- F_SETLKW:给文件加上进程锁,如果此文件之前已经被加了锁,则一直等待锁被释放。
接下来看两段代码:
#include <fcntl.h> #include <unistd.h> #include <cstring> #include <cstdio> #include <cstdlib>#define ERR_EXIT(msg) \do \{ \perror(msg); \exit(-1); \} while(0)int main() {int fd = open("test.dat", O_CREAT | O_RDWR | O_TRUNC, 0644);if (fd < 0)ERR_EXIT("open file failed");struct flock f;memset(&f, 0, sizeof(f));f.l_type = F_WRLCK;f.l_whence = SEEK_SET;f.l_start = 0;f.l_len = 0;if (fcntl(fd, F_SETLK, &f) < 0)ERR_EXIT("lock file failed");printf("press any key to unlock\n");getchar();f.l_type = F_UNLCK;if (fcntl(fd, F_SETLK, &f) < 0)ERR_EXIT("unlock file failed");return 0; }
上述代码实现了加锁和解锁两个操作。
#include <unistd.h> #include <fcntl.h> #include <cstdio> #include <cstdlib> #include <cerrno> #include <sys/types.h> #include <sys/stat.h>#define ERR_EXIT(msg) \do \{ \perror(msg); \exit(-1); \} while(0)void set_flag(int fd, int flags); void clr_flag(int fd, int flags);int main() {char buf[1024];set_flag(0, O_NONBLOCK);int ret = read(0, buf, 1024);if (ret < 0)ERR_EXIT("read failed");return 0; }void set_flag(int fd, int flags) {int val = fcntl(fd, F_GETFL, 0); if (val < 0)ERR_EXIT("get flag failed");val |= flags;if (fcntl(fd, F_SETFL, val) < 0)ERR_EXIT("set flag failed"); } void clr_flag(int fd, int flags) {int val = fcntl(fd, F_GETFL, 0);if (val < 0)ERR_EXIT("get flag failed");val &= ~flags;if (fcntl(fd, F_SETFL, val) < 0)ERR_EXIT("set flag failed"); }
其中set_flag设置文件状态标识,clr_flag清除文件状态标识。main函数中将stdout设置成非阻塞,所以执行read时,不等待用户输入而直接返回错误。