一.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
明天:
一.進程的基本控制
二.進程的高級控制-信號