Unix C (五)

系统调用
 系统调用可以操作内核,是外部程序和内核层交互的接口,但不能过于频繁的调用,否则效率极低。
  time命令可以查看用户层及其内核层的执行时间。
文件和目录
 在Linux/Unix中,几乎一切都可以被看成文件。
 因此,系统调用函数open/close/read/write/ioctl几乎可以通用。  
 在Unix的系统调用中,打开/创建一个文件会产生一个文件表,这个文件表用非负整数代表,这个非负整数叫文件描述符。系统默认占有0/1/2,因此文件描述符从3开始。文件描述符关闭后可以循环使用。

Unix系统调用之 - 文件相关函数

 文件描述符 - 本身是一个数字,对应一张文件表
  文件的信息都记录在文件表中
  (open)
 利用文件描述符可以进行各种操作(read/write)
   
fcntl函数可以用于操控文件的状态和文件锁定,格式
 int fcntl(int fd,int cmd,...)
 cmd常用的有:()里边是第三个参数
   F_DUPFD(long) 复制文件描述符,但不会强制关闭
   F_GETFL(void) 取文件的访问模式和文件状态
   F_SETFL(long) 不包括 创建状态

   F_SERLK/F_SETLKW/F_GETLK 文件锁相关


实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
  int fd=open("a.txt",O_RDWR|O_CREAT|O_APPEND,0666);
  if(fd==-1) perror("open"),exit(-1);


  //复制文件描述符,如果没有使用返回参数值,如果使用了,返回比参数大的第一个没有使用的值
  int fd2 = fcntl(fd,F_DUPFD,5);//返回5
  int fd3 = fcntl(fd,F_DUPFD,5);//返回6,不是4
  printf("fd=%d,fd2=%d,fd3=%d\n",fd,fd2,fd3);


  int flags = fcntl(fd,F_GETFL);
  printf("flags=%d\n",flags);
  if((flags&3) == 2) printf("RDWR\n");
  if((flags&3) == 1) printf("WRONLY\n");
  if((flags&3) == 0) printf("RDONLY\n");
  if(flags & O_APPEND) printf("Append\n");


  //flags不记录创建标志O_CREAT/TRUNC/EXCL
  if(flags & O_CREAT) printf("create\n");


  //访问权限是不能修改
  fcntl(fd,F_SETFL,O_WRONLY);
  flags = fcntl(fd,F_GETFL);
  printf("flags=%d\n",flags);
  if((flags&3) == 2) printf("RDWR\n");
  if((flags&3) == 1) printf("WRONLY\n");
  if((flags&3) == 0) printf("RDONLY\n");
  if(flags & O_APPEND) printf("Append\n");
  close(fd);


  return 0;
}

 
文件锁可以控制多个进程对文件的同时操作,但不能防止人为读写文件(vi/gedit/...)。可以控制文件的位置,也就是可以锁定文件的某部分。结构体flock用于记录锁的信息。
  struct flock{
    short l_type; //锁的类型 包括读锁/写锁/解锁
    short l_whence;//锁的起始位置参照
    int l_start; //偏移量
    int l_len; //锁定长度
    pid_t l_pid;//上锁进程id,一般给-1即可
  };
  l_whence 使用seek的参数 SEEK_SET/SEEK_CUR/SEEK_END,与l_start参数一起决定开始锁定的位置。
  读写锁:
  F_RDLCK 读锁  
   读锁其实锁定的是其他的写进程,不锁定其他的读进程。读文件(不能写)的进程使用,是共享锁。
  F_WRLCK 写锁
   写锁锁定其他所有进程。写文件时使用,是独占锁
 
 锁其实只是作为 read/write的条件,而不是真正锁定文件。能上锁分支就可以读写,不能上锁分支不要读写
 
 上锁时可以指定为等待其它锁结束后再锁定方式(阻塞),fcntl(fd,F_SETLKW,&lock) 即可。
   
  F_GETLK 不是加锁,也不是取锁,是测试能否加锁。

  如果能加,把lock的l_type变成F_UNLCK,但不真正加锁。如果不能加,把当前的锁放入lock中返回。


实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main(){
  int fd = open("a.txt",O_RDWR);
  if(fd==-1) perror("open"),exit(-1);
  struct flock rlock;
  rlock.l_type = F_RDLCK;
  rlock.l_whence = SEEK_SET;
  rlock.l_start = 0;
  rlock.l_len = 20;
  rlock.l_pid = -1;
  int res = fcntl(fd,F_GETLK,&rlock);
  printf("rdlk=%d,wrlk=%d,unlk=%d\n",F_RDLCK,F_WRLCK,F_UNLCK);
  printf("type=%d,pid=%d\n",rlock.l_type,rlock.l_pid);
  if(res == -1) perror("GetLock"),exit(-1);
  if(rlock.l_pid == -1){//常用pid判断
    printf("可以加读锁\n");
  }else{
    printf("不可以加读锁\n");
  }
  rlock.l_type = F_WRLCK;
  res = fcntl(fd,F_GETLK,&rlock);
  if(res == -1) perror("GetLock"),exit(-1);
  if(rlock.l_pid == -1){//常用pid判断
    printf("可以加写锁\n");
  }else{
    printf("不可以加写锁\n");
  }
  printf("type=%d,pid=%d\n",rlock.l_type,rlock.l_pid);

  close(fd);


  return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章