歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

《APUE》:死鎖檢測實例

《Unix環境高級編程》這本書附帶了許多短小精美的小程序,我在閱讀此書的時候,將書上的代碼按照自己的理解重寫了一遍(大部分是抄書上的),加深一下自己的理解(純看書太困了,呵呵)。此例子在Ubuntu 10.04上測試通過。

相關鏈接

  • 《UNIX環境高級編程》(第二版)apue.h的錯誤 http://www.linuxidc.com/Linux/2011-04/34662.htm
  • Unix環境高級編程 源代碼地址 http://www.linuxidc.com/Linux/2011-04/34826.htm

程序簡介:這個例子是一個會發生死鎖的程序。

  1. //《APUE》程序14-2:加鎖和解鎖一個文件區域  
  2. //《APUE》程序14-4:死鎖檢測實例  
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <unistd.h>  
  6. #include <fcntl.h>  
  7. #include <errno.h>  
  8. #include <signal.h>  
  9. #include <sys/stat.h>   
  10.  
  11. #define read_lock(fd, offset, whence, len) \  
  12.     lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len)) 
  13. #define readw_lock(fd, offset, whence, len) \  
  14.     lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len)) 
  15. #define write_lock(fd, offset, whence, len) \  
  16.     lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len)) 
  17. #define writew_lock(fd, offset, whence, len) \  
  18.     lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len)) 
  19. #define un_lock(fd, offset, whence, len) \  
  20.     lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len)) 
  21.  
  22. #define FILE_MODE   (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)  
  23.  
  24. sig_atomic_t sigflag; /* set nonzero by sig handler */ 
  25. sigset_t newmask, oldmask, zeromask; 
  26.  
  27. //輸出錯誤信息並退出     
  28. void error_quit(const char *str)     
  29. {     
  30.     fprintf(stderr, "%s\n", str);     
  31.     exit(1);     
  32.  
  33. static void sig_usr(int signo)  /* one signal handler for SIGUSR1 and SIGUSR2 */ 
  34.     sigflag = 1; 
  35.  
  36. void TELL_WAIT(void
  37.     if (signal(SIGUSR1, sig_usr) == SIG_ERR) 
  38.         error_quit("signal(SIGUSR1) error"); 
  39.     if (signal(SIGUSR2, sig_usr) == SIG_ERR) 
  40.         error_quit("signal(SIGUSR2) error"); 
  41.     sigemptyset(&zeromask); 
  42.     sigemptyset(&newmask); 
  43.     sigaddset(&newmask, SIGUSR1); 
  44.     sigaddset(&newmask, SIGUSR2); 
  45.  
  46.     /* 
  47.     * Block SIGUSR1 and SIGUSR2, and save current signal mask. 
  48.     */ 
  49.     if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) 
  50.         error_quit("SIG_BLOCK error"); 
  51.  
  52. void TELL_PARENT(pid_t pid) 
  53.     kill(pid, SIGUSR2);     /* tell parent we're done */ 
  54.  
  55. void WAIT_PARENT(void
  56.     while (sigflag == 0) 
  57.         sigsuspend(&zeromask);  /* and wait for parent */ 
  58.     sigflag = 0; 
  59.  
  60.     /* 
  61.     * Reset signal mask to original value. 
  62.     */ 
  63.     int temp = sigprocmask(SIG_SETMASK, &oldmask, NULL); 
  64.     if (temp < 0) 
  65.         error_quit("SIG_SETMASK error"); 
  66.  
  67. void TELL_CHILD(pid_t pid) 
  68.     kill(pid, SIGUSR1);         /* tell child we're done */ 
  69.  
  70. void WAIT_CHILD(void
  71.     while (sigflag == 0) 
  72.         sigsuspend(&zeromask);  /* and wait for child */ 
  73.     sigflag = 0; 
  74.  
  75.     /* 
  76.     * Reset signal mask to original value. 
  77.     */ 
  78.     int temp = sigprocmask(SIG_SETMASK, &oldmask, NULL); 
  79.     if (temp < 0) 
  80.         error_quit("SIG_SETMASK error"); 
  81.  
  82. //加鎖或解鎖某個文件區域  
  83. int lock_reg(int fd, int cmd, int type, off_t offset, 
  84.              int whence, off_t len) 
  85.     struct flock lock; 
  86.     lock.l_type = type; 
  87.     lock.l_start = offset; 
  88.     lock.l_whence = whence; 
  89.     lock.l_len = len; 
  90.     return fcntl(fd, cmd, &lock); 
  91.  
  92. //鎖住文件中的一個字節  
  93. void lockabyte(const char *name, int fd, off_t offset) 
  94.     //在我的系統上(Ubuntu10.04),發生死鎖時writew_lock並不會返回-1  
  95.     if( writew_lock(fd, offset, SEEK_SET, 1) < 0 ) 
  96.         error_quit("writew_lock error"); 
  97.     printf("%s: got the lock, byte %ld\n", name, offset); 
  98.  
  99. int main(void
  100.     int fd; 
  101.     pid_t pid; 
  102.  
  103.     fd = creat("templock", FILE_MODE); 
  104.     if( fd < 0 ) 
  105.         error_quit("create error"); 
  106.     if( write(fd, "ab", 2) != 2 ) 
  107.         error_quit("write error"); 
  108.  
  109.     TELL_WAIT(); 
  110.     pid = fork(); 
  111.     if( pid < 0 ) 
  112.         error_quit("fork error"); 
  113.     else if( pid == 0 ) 
  114.     { 
  115.         lockabyte("child", fd, 0); 
  116.         TELL_PARENT( getpid() ); 
  117.         WAIT_PARENT(); 
  118.         lockabyte("child", fd, 1); 
  119.     } 
  120.     else 
  121.     { 
  122.         lockabyte("parent", fd, 1); 
  123.         TELL_CHILD(pid); 
  124.         WAIT_CHILD(); 
  125.         lockabyte("parent", fd, 0); 
  126.     } 
  127.     return 0; 

注解:

1:在該程序中,子進程鎖住字節0,父進程鎖住字節1,然後,它們又都試圖鎖住對方已經加鎖的字節,這樣就造成了死鎖。

2:《Unix環境高級編程》上說:檢測到死鎖時,內核必須選擇一個進程出錯返回。但在我的系統中,父子進程都被卡住,只有當你強制中斷時(Ctrl+C)時,程序才會結束。這個問題以後找個時間來研究一下。

Copyright © Linux教程網 All Rights Reserved