1 使用宏来减少函数定义,简化函数调用
recode_lock.h
#ifndef ___RECODE_LOCK__ #define ___RECODE_LOCK__ #include <unistd.h> #include <fcntl.h> #include <stdlib.h> /* 加非阻塞读锁 */ #define read_lock(fd, l_whence, l_start, l_len) \ lock_set(fd, F_SETLK, F_RDLCK, l_whence, l_start, l_len) /* 加阻塞读锁 */ #define read_lockw(fd, l_whence, l_start, l_len) \ lock_set(fd, F_SETLKW, F_RDLCK, l_whence, l_start, l_len) /* 加非阻塞写锁 */ #define write_lock(fd, l_whence, l_start, l_len) \ lock_set(fd, F_SETLK, F_WRLCK, l_whence, l_start, l_len) /* 加阻塞写锁 */ #define write_lockw(fd, l_whence, l_start, l_len) \ lock_set(fd, F_SETLKW, F_WRLCK, l_whence, l_start, l_len) /* 解锁 */ #define unlock(fd, l_whence, l_start, l_len) \ lock_set(fd, F_SETLK, F_UNLCK, l_whence, l_start, l_len) /* 操作锁的函数 */ static int lock_set(int fd, int l_ifwset, short l_type, short l_whence, \ off_t l_start, off_t l_len) { int ret = -1; struct flock f_lock; f_lock.l_type = l_type; f_lock.l_whence = l_whence; f_lock.l_start = l_start; f_lock.l_len = l_len; ret = fcntl(fd, l_ifwset, &f_lock);//加锁解锁 return(ret); } #endif
helloworld.c
#include <stdio.h> #include <stdlib.h> #include "recode_lock.h" int main(void) { int ret = 0, fd = -1; fd = open("./file", O_CREAT|O_RDWR|O_APPEND|O_TRUNC, 0777); if(fd < 0) { perror("open is fail"); exit(-1); } while(1) { //加阻塞读锁,也就是加锁失败,程序会休眠在这里,就像scanf没有数据,也会休眠一样 read_lockw(fd, SEEK_SET, 0, 0); write(fd, "hello ", 6); write(fd, "world\n", 6); unlock(fd, SEEK_SET, 0, 0); //解锁 } }
(1)分析这些宏
像这类宏参数很多,密密麻麻,很多同学一看到这种宏就讨厌,但是不用担心,分析这类比较复杂的宏定义时是有办法的,办法就是进行宏的替换操作,找到本源后自然就能理解了。
当然还有一个办法,那就是查看预编译后的替换结果,不过这样还不如层层替换后分析本源来的更直观。
分析的结果总结:
所有带参宏的宏体都指向同一个函数lock_set,通过不同的带参宏去调用lock_set函数,就实现了不同的功能,那为什么要这么做呢?为什么不直接定义6个加锁、解锁的函数呢?
(2)为什么要费劲的写这些个复杂的带参宏
通过前面的介绍我们知道,这个程序的作用是实现对文件的加锁和解锁,可以实现的操作有
加非阻塞读锁
加阻塞读锁
加非阻塞写锁
加阻塞写锁
解锁
其实最终是调用fcntl函数来加锁、解锁的,不过为了调用更方便,我们需要进行进一步的函数封装,其中最笨的方式是定义六个函数,分别是想上述功能。
但是最后发现一个现象,那就是所有函数想要做的事情都是一样的,都是去设置文件锁的属性,每个函数的代码内容几乎一模一样,函数功能的不同仅仅只是靠参数值的不同来体现的。
像这种情况,我们定义6个函数来实现,代码其实并不简洁,而且定义这些函数还很花费时间,此时我们就可以使用带参宏来实现,不仅减少了函数的定义,而且还简化了参数。
能够写死的参数就直接在宏体中写死,调用带参宏时,只填写必须要写的参数。