1. 程式人生 > >linux高階程式設計day05 筆記 (轉)

linux高階程式設計day05 筆記 (轉)

一.IO與檔案目錄管理
 1.pread=lseek+read
   pread讀取以後不改變讀寫位置
 2.mmap對映:
   /proc/${pid}/mem 無法對映
 3.IO的有效使用者與實際使用者
   預設情況:實際使用者與有效使用者一致。  
   實際使用者:執行使用者
   有效使用者:許可權使用者
   uid_t getuid()
   uid_t geteuid()
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

main()
{
    int
 fd;
    char buf[1025];
    int r;
    printf("real user:%d\n",getuid());
    printf("effective user:%d\n",geteuid());
    
    fd=open("../day05",O_RDWR);
    if(fd==-1) printf("open error:%m\n"),exit(-1);
    bzero(buf,1024);
    
    while((r=read(fd,buf,1024))>0)
    {
        buf[r]=0;
        printf("%s",buf);
    }
    close(fd);
}

4.目錄相關函式
    chdir 切換目錄
    mkdir 建立目錄
    rmdir 刪除目錄
    unlink 刪除檔案
    umask 設定檔案許可權遮蔽位
    stat 檔案目錄狀態

 5.目錄的遍歷
   opendir系列函式
   readdir
   closedir
   seekdir
   dirfd


#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
main()
{
    DIR *d;
    struct dirent *de;
    //開啟目錄    d=opendir("/home");
    if(d==NULL)
    {
        printf("opendir:%m\n");
        exit(-1);
    }
    //
迴圈讀取目錄    while(de=readdir(d))
    {
        printf("%s,\t%d\n",de->d_name,de->d_type);
    }
    
    //關閉目錄    closedir(d);
}int scandir(const char*dirname,//目錄名                struct dirent***namelist,//返回目錄列表                int (*)(struct dirent*),//回撥函式,過濾目錄
                                                            
//NULL:不過濾                int (*)(struct dirent*,struct dirent*)//排序返回目錄
                                                
//NULL:不排序                ); 返回: 
     >=0 目錄個數
     =-1 目錄查詢失敗
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
int mysort(const void*d1,const void*d2)
{
    return -alphasort(d1,d2);
}
int myfilter(const struct dirent*d)
{
    if(memcmp(d->d_name,".",1)==0)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}
main()
{
    struct dirent**d;
    int r;
    int i;
    r=scandir("/home",&d,myfilter,mysort);
    printf("子目錄個數:%d\n",r);
    for(i=0;i<r;i++)
    {
        printf("%s\n",d[i]->d_name);
    }
    /*
    while(*d)
    {
        printf("%s\n",(*d)->d_name);
        d++;
    }
    
*/
}二.程序
  1.什麼是程序
    執行的程式:程式碼->資源->CPU
    程序有很多資料維護:程序狀態/程序的屬性
    所有程序屬性採用的結構體維護->樹形資料結構
    ps 察看程序常見屬性
    top 察看系統程序執行狀況
    pstree(ptree)
    kill 向程序傳送訊號
       kill  -s 訊號 程序id
       kill -l 顯示程序能接受的所有訊號
   知道程序有很多屬性:ps可以察看的屬性

  2.建立程序
    1.程式碼?載入到記憶體?分配CPU時間片?
     程式碼由獨立的程式存在.
    2.程序有關的建立函式
     int system(const char*filename);
       建立獨立程序,擁有獨立的程式碼空間,記憶體空間
       等待新的程序執行完畢,system才返回.(阻塞)
案例:
  使用system呼叫一個程式。
  觀察程序ID。 
  觀察阻塞。
     新的返回值與system返回值有關係。
     任何程序的返回值:不要超過255。一個位元組。
     system的返回值中8-15位存放返回碼
練習:
  使用system呼叫"ls -l"。"ls -l home"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
main()
{
    int r;
    printf("%d\n",getpid());
    r=system("ls -l ");
    //printf("%d\n",r>>8&255);    printf("%d\n",WEXITSTATUS(r));
    system("clear");
}   子程序:被建立程序。
    父程序:相對被建立者的程序。       

     popen:建立子程序
         在父子程序之間建立一個管道
案例:
   使用popen呼叫ls -l,並且建立一個管道讀取輸出
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
main()
{
    char buf[1024];
    FILE *f=popen("ls -l","r");
    int fd=fileno(f);
    
    int r;    
    printf("=============\n");
    
    while((r=read(fd,buf,1024))>0)
    {
        buf[r]=0;
        printf("::%s\n",buf);
    }
    printf("=============\n");
    
    close(fd);
    pclose(f);    
}    exec系列函式:
     execl   execlp 
     替換當前程序的程式碼空間中的程式碼資料
     函式本身不建立新的程序。
     int  execl(const char*path,const char *arg,....);
     第一個引數:替換的程式,
     第二個引數....:命令列   
        命令列格式:命令名  選項引數
        命令列結尾必須空字串結尾
案例:
   使用exec執行一個程式。
   體會:*是否建立新的程序?沒有
      *體會execl的引數的命令列的格式
      *體會execl與execlp的區別(execl只當前路徑)
         execlp 使用系統的搜尋路徑
      *體會execl替換當前程序的程式碼
#include <stdio.h>
#include <unistd.h>  
int main()
{
    //printf("main:%d\n",getpid());    int r=execlp("ls","ls","-l",NULL);
    printf("結束%d\n",r);
    return 0;
}   fork
     pid_t  fork();
     //1.建立程序
     //2.新程序的程式碼是什麼:克隆父程序的程式碼
        而且克隆了執行的位置.
     //3.在子程序不呼叫fork所以返回值=0;
     //4.父子程序同時執行.#include <stdio.h>
#include <unistd.h>  
int main()
{
    int pid;
    
    printf("建立程序前!\n");
    pid=fork();
    if(pid==0)
    {
        while(1)
        {
            printf("子程序\n");
            sleep(1);
        }    
    }
    else
    {
        while(1)
        {
            printf("父程序\n");
            sleep(1);
        }
    }
    return 0;
}  3.應用程序
   使用fork建立新的程序有什麼應用價值呢?
   使用fork實現多工.(Unix系統本身是不支援執行緒)
       1.程序
       2.執行緒
       3.訊號
       4.非同步
       5.程序池與執行緒池
案例:
   使用程序建立實現多工   
   1.UI
   2.建立多工框架
   3.分別處理不同的任務 
#include <curses.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

WINDOW *wtime,*wnumb;
main()
{
    initscr();
    wtime=derwin(stdscr,3,10,0,(COLS-10));
    wnumb=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
    box(wtime,0,0);
    box(wnumb,0,0);
    refresh();
    wrefresh(wtime);
    wrefresh(wnumb);
    if(fork())
    {//show time        time_t tt;
        struct tm *t;
        while(1)
        {
            time(&tt);
            t=localtime(&tt);
            mvwprintw(wtime,1,1,"%02d:%02d:%02d",
                t->tm_hour,t->tm_min,t->tm_sec);
            refresh();    
            wrefresh(wtime);
            wrefresh(wnumb);
            sleep(1);
        }
    }
    else
    {//show number        int num=0;
        int i;
        while(1)
        {
            num=0;
            for(i=0;i<7;i++)
            {
                num=num*10+rand()%10;
            }
            mvwprintw(wnumb,1,2,"%07d",num);
            refresh();    
            wrefresh(wtime);
            wrefresh(wnumb);
            usleep(10000);
        }
    }
    endwin();    
}  4.理解程序
   1.父子程序的關係
     獨立的兩個程序
     互為父子關係
   2.問題:
      2.1.父程序先結束?
        子程序就依託根程序init:孤兒程序
        孤兒程序沒有任何危害.        
      2.2.子程序先結束?
        子程序會成為僵死程序.
        僵死程序不佔用記憶體,CPU.但在程序任務管理樹佔用一個節點.
        僵死程序造成程序名額資源浪費.
        所以處理僵死程序.
   3.僵死程序使用wait回收

   4.父程序怎麼知道子程序退出?
    子程序結束通常會向父程序傳送一個訊號
      SIGCHLD 
   5.父程序處理子程序退出訊號
     signal(int sig,void(*fun)(int));
     向系統註冊:只要sig訊號發生,系統停止程序,並呼叫函式fun
     當函式執行完畢,繼續原來程序
     5.1.實現處理函式
     5.2.使用signal邦定訊號與函式   
僵死程序回收案例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
void deal(int s)
{
    int status;
    wait(&status);
    printf("回收中..\n");
    sleep(5);    
    printf("回收完畢:%d!\n",WEXITSTATUS(status));
            
}
main()
{
    if(fork()==0)
    {
        //child        printf("child!\n");
        sleep(20);
        printf("退出!\n");
        exit(88);
    }
    else
    {        
        //parent        signal(17,deal);
        while(1)
        
{
        
    printf("parent!\n");        
        
    sleep(1);
        
}        //sleep(20000); 這裡父程序也會被sigchld訊號喚醒,在執行完訊號處理程式後,繼續向下執行
        printf("parent!\n");
    }
} 6.父子程序的資源訪問
     6.1.記憶體資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
main()
{
    /*
    int *a=mmap(0,4,PROT_READ|PROT_WRITE,
            MAP_ANONYMOUS|MAP_PRIVATE,0,0);
            
*/
    int *a=sbrk(4);        
    *a=40;    
    if(fork())
    {
        printf("parent:%d\n",*a);
        *a=90;
    }
    else
    {
        printf("child:%d\n",*a);
        sleep(3);
        printf("child:%d\n",*a);        
    }
    
}6.2.檔案資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>
main()
{
    
    if(fork())
    {
        int fd=open("test.txt",O_RDWR);
        printf("%d\n",fd);
        sleep(5);
        write(fd,"Killer",6);        
        close(fd);
    }
    else
    {
        int fd=open("test.txt",O_RDWR);
        printf("%d\n",fd);
        write(fd,"Clinton",7);
        sleep(8);
        close(fd);
    }
}

案例:
  說明:子程序克隆整個記憶體區域,
     但記憶體區域指向不同的物理空間
     儘管克隆,但記憶體獨立. 不能相互訪問.
     
     多程序實現多工,程序之間的資料交換是大問題.(IPC)
     Inter-Process Commucation
     
     對映記憶體:
        MAP_SHARED:對映到同一實體記憶體
        MAP_PRIVATE:對映到不同的實體記憶體.
     
案例:
  兩個程序之間,檔案描述符號指向的是同一個檔案核心物件.   

回顧:
  1.目錄遍歷   
  2.程序建立system popen exec fork
  3.僵死程序出現的條件以及回收
  4.利用多程序實現簡單的多工
  5.理解程序的克隆.

作業:
  1.使用兩個程序,查詢素數:(多工)
    A程序查詢1-5000
    B程序查詢5001-10000
    把素數寫入檔案.
  2.寫一個多工:(兩個程序資料共享)
    A.程序查詢素數,放入mmap分配的空間
    B.程序把mmap的資料取出來,判定兩個資料是否相鄰.
      相鄰就列印這兩個素數.
思考:      
  3.使用opendir/readir遍歷指定目錄下的所有*.c檔案.
     scandir 

明天:
  一.程序的基本控制
  二.程序的高階控制-訊號