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;
}

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