文件上锁lockf() 和fcntl()

Linux中,实现文件上锁的函数有lockf() 和fcntl() ,其中lockf()用于对文件施加建议性锁,而fcntl() 不仅可以施加建议性锁,而且可以施加强制性锁。fcntl()还能对文件的某一记录上锁,也就是记录锁。记录锁又可分读取锁(共享锁)和写入锁(排斥锁),文件的同一部分不能同时建立读取锁和写入锁。


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. #include <sys/types.h>  
  4.   
  5. #include <unistd.h>  
  6.   
  7. #include <sys/wait.h>  
  8.   
  9. #include <sys/types.h>  
  10.   
  11.    
  12.   
  13. #define PATH "/tmp/count"  
  14.   
  15.    
  16.   
  17.    
  18.   
  19. FILE *fd;//将文件指针定义为全局变量。  
  20.   
  21. static void* add_fun(void)  
  22.   
  23. {  
  24.   
  25.     char buf[256];  
  26.   
  27.    
  28.   
  29.     lockf(fileno(fd), F_LOCK, 0);//同样在获取数据之前加锁  
  30.   
  31.     fgets(buf, 256, fd);  
  32.   
  33.     usleep(1);  
  34.   
  35.     lseek(fileno(fd), 0, SEEK_SET);//写入之前使文件指针回复到文件头  
  36.   
  37.     fprintf(fd, "%d\n", atoi(buf) + 1);  
  38.   
  39.     fflush(fd);  
  40.   
  41.    
  42.   
  43.     lseek(fileno(fd), 0, SEEK_SET);//注意这里在关闭文件之前比程序一多了一次将文件当前指针回复到文件头的操作,如果没有此操作会出错。因为所有的子进程共用了一个inode,同时文件当前位置的信息就在inode中,所以如果这里不回复的话,其它子进程在读取的时候就不会从文件的头读取了。  
  44.   
  45.     lockf(fileno(fd), F_ULOCK, 0);  
  46.   
  47.     fclose(fd);//如果没有上面的fflush的话即使将fclose放在解锁之前也不可以。注意这里即使使用的是同一个inode,但要是进行close文件,如果当前close的文件不是最后一个引用的进程则只是将文件的引用计数减一。只有在close最后一个时才会释放inode。  
  48.   
  49.    
  50.   
  51.     return NULL;  
  52.   
  53. }  
  54.   
  55.    
  56.   
  57. int main(void)  
  58.   
  59. {  
  60.   
  61.    
  62.   
  63.     pid_t pid[10];  
  64.   
  65.     int i;  
  66.   
  67.     fd = fopen(PATH, "r+");//在创建子进程之前打开的文件。子进程会继承父进程打开的文件。但需要注意的是,在整个程序中,只open了一次,所以在内存中只有一个inode结构体。  
  68.   
  69.     if (fd == NULL){  
  70.   
  71.         perror("open()");  
  72.   
  73.         pthread_exit(NULL);  
  74.   
  75.     }  
  76.   
  77.       
  78.   
  79.     for(i = 0; i < 10; i++){  
  80.   
  81.         pid[i] = fork();  
  82.   
  83.         if (pid[i] == 0){  
  84.   
  85.             add_fun();  
  86.   
  87.             return 0;  
  88.   
  89.         }  
  90.   
  91.     }  
  92.   
  93.     for(i = i; i < 10; i++){  
  94.   
  95.         wait(NULL);  
  96.   
  97.     }  
  98.   
  99.     return 0;  
  100.   
  101.           
  102.   
  103. }  
  104.   
  105.    
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. #include <sys/types.h>  
  4.   
  5. #include <unistd.h>  
  6.   
  7. #include <sys/wait.h>  
  8.   
  9. #include <sys/types.h>  
  10.   
  11.    
  12.   
  13. #define PATH "/tmp/count"  
  14.   
  15.    
  16.   
  17. static void* add_fun(void)  
  18.   
  19. {  
  20.   
  21.     FILE* fd;//这里使用文件指针是因为在使用fprintf时只能使用文件指针,同时文件指针可以通过fileno函数实现文件描述符的转换。  
  22.   
  23.     char buf[256];  
  24.   
  25.     fd = fopen(PATH, "r+");  
  26.   
  27.     if (fd == NULL){  
  28.   
  29.         perror("open()");  
  30.   
  31.         pthread_exit(NULL);//为什么使用这个??  
  32.   
  33.     }  
  34.   
  35.     lockf(fileno(fd), F_LOCK, 0);//在读取文件的数据之前加锁,而不是在打开文件之前加锁。因为文件是在每个子进程中打开的,所以每个子进程都有自己的inode。Open的过程就是创建属于当前进程文件的inode结构体。所以不用考虑inode的互斥问题。理论上互斥的代码段越短程序的性能越好。  
  36.   
  37.     fgets(buf, 256, fd);//通过调用fgets函数获取文件的第一行数据。  
  38.   
  39.     usleep(3);//这里睡眠是因为可以使得在没有使用文件锁的时候累加结果不准确更容易产生。  
  40.   
  41.     lseek(fileno(fd), 0, SEEK_SET);//记得在写入之前要将文件的当前位置回复到文件的开头。  
  42.   
  43.     fprintf(fd, "%d\n", atoi(buf) + 1);//注意从文件读取的数据都是字符型的,可以通过atoi函数将其转换成int型。Fprintf函数有时很有用的。  
  44.   
  45.     fflush(fd);//注意这里要对文件进行刷新,只有这样才能在下面的解锁之前保证数据真正的写入了磁盘文件中。当然也可以把fcolse放在解锁之前,这时就不用fflush了。  
  46.   
  47.    
  48.   
  49.     lockf(fileno(fd), F_ULOCK, 0);  
  50.   
  51.    
  52.   
  53.     fclose(fd);  
  54.   
  55.    
  56.   
  57.     return NULL;  
  58.   
  59. }  
  60.   
  61.    
  62.   
  63. int main(void)  
  64.   
  65. {  
  66.   
  67.     int fd;  
  68.   
  69.     pid_t pid[10];  
  70.   
  71.     int i;  
  72.   
  73.       
  74.   
  75.     for(i = 0; i < 10; i++){  
  76.   
  77.         pid[i] = fork();  
  78.   
  79.         if (pid[i] == 0){  
  80.   
  81.             add_fun();  
  82.   
  83.             return 0;//子进程执行到这就退出了。  
  84.   
  85.         }  
  86.   
  87.     }  
  88.   
  89.     for(i = i; i < 10; i++){  
  90.   
  91.         wait(NULL);  
  92.   
  93.     }  
  94.   
  95.     return 0;  
  96.   
  97.           
  98.   
  99. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值