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时,不等待用户输入而直接返回错误。