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