冠县网站设计,租车网站制作方案,罗湖装修公司网站建设,做网站首页图片素材一、Xmind整理#xff1a; 父进程会拷贝文件描述符表给子进程#xff1a; 二、课上练习#xff1a;
练习1#xff1a;①从终端获取一个文件的路径以及名字。②若该文件是目录文件#xff0c;则将该文件下的所有文件的属性显示到终端#xff0c;类似ls -l该文件夹③若该文…一、Xmind整理 父进程会拷贝文件描述符表给子进程 二、课上练习
练习1①从终端获取一个文件的路径以及名字。②若该文件是目录文件则将该文件下的所有文件的属性显示到终端类似ls -l该文件夹③若该文件不是目录文件则显示该文件的属性到终端上类似ls -l这单个文件
include stdio.h
include string.h
include stdlib.h
include head.h
/获取文件类型
har get_fileType(mode_t m)switch(mS_IFMT){case S_IFSOCK:return(s);break;case S_IFLNK:return(l);break;case S_IFREG:return(-);break;case S_IFDIR:return(d);break;case S_IFCHR:return(c);break;case S_IFBLK:return(b);break;case S_IFIFO:return(p);break;}/获取文件权限
oid get_filePermission(mode_t m)for(int i0;i9;i){if((m(0400i))0){putchar(-);continue;}//能运行到当前位置则代表对应位置有权限//需要判断是r w x当中的哪一个switch(i%3){ case 0:putchar(r);break;case 1:putchar(w);break;case 2:putchar(x);break;}}return;nt getstat(struct stat buf,char *str)//文件的类型和权限char typeget_fileType(buf.st_mode);printf(%c,type);get_fileType(buf.st_mode);//文件的硬链接数printf(%ld , buf.st_nlink);//文件的所属用户//printf(uid: %d\n, buf.st_uid);//将uid转换成名字struct passwd* pwd getpwuid(buf.st_uid);if(NULL pwd){ERR_MSG(getpwuid);return -1;}printf(%s , pwd-pw_name);//文件所属组用户//printf(gid: %d\n, buf.st_gid);//将gid转换成名字struct group* grp getgrgid(buf.st_gid);if(NULL grp){ERR_MSG(getgrgid);return -1;}printf(%s , grp-gr_name);//文件大小printf(%ld , buf.st_size);//文件的修改时间struct tm* infoNULL;infolocaltime(buf.st_mtime);//printf(%ld ,buf.st_ctime);printf(%02d %02d %02d:%02d ,info-tm_mon1,info-tm_mday,info-tm_houprintf(%s\n,str);nt main(int argc, const char *argv[])char str[20];char path[300];char type0;struct stat buf;DIR* dpNULL;struct dirent* rpNULL;//从终端获取一个文件的路径以及名字printf(please enter a filename:);scanf(%s,str);getchar();//判断文件是否是目录文件if(stat(str,buf) 0){ERR_MSG(stat);return -1;}typeget_fileType(buf.st_mode);if(dtype){//文件是一个目录文件则需要打开目录dp opendir(str);if(NULL dp){ERR_MSG(opendir);return -1;}printf(open success \n);while(1){//循环读取目录rp readdir(dp);if(NULL rp){if(0 errno){printf(读取完毕\n);break;}else{ERR_MSG(readdir);return -1;}}//将读取到的文件名传入stat获取属性sprintf(path,%s%s,str,rp-d_name);//printf(path:%s\n,path);if(stat(path,buf)0){ERR_MSG(stat);return -1;}getstat(buf,rp-d_name);// printf([%d]%s\n,i,rp-d_name);}closedir(dp);}elsegetstat(buf,str);return 0; 练习2文件IO函数实现拷贝文件。子进程先拷贝后半部分父进程再拷贝前半部分。允许使用sleep函数
#include stdio.h
#include head.h
#include sys/stat.h
#include sys/types.h
#include fcntl.h
#include unistd.hint main(int argc, const char *argv[])
{int fd_r open(./1.png, O_RDONLY);if(fd_r 0){ERR_MSG(open);return -1;}int fd_w open(copy.png, O_WRONLY|O_CREAT|O_TRUNC, 0644);if(fd_w 0){ERR_MSG(open);return -1;}//计算文件大小off_t size lseek(fd_r, 0, SEEK_END);pid_t cpid fork();if(cpid 0){sleep(4);//父进程拷贝前半部分//将偏移量修改到0lseek(fd_r, 0, SEEK_SET);lseek(fd_w, 0, SEEK_SET);char c 0;for(int i0; isize/2; i){read(fd_r, c, 1);write(fd_w, c, 1);}printf(前半部分拷贝完毕\n);}else if(0 cpid){ //子进程拷贝后半部分//将偏移量修改到size/2lseek(fd_r, size/2, SEEK_SET);lseek(fd_w, size/2, SEEK_SET);char c 0;for(int isize/2; isize; i){read(fd_r, c, 1);write(fd_w, c, 1);} printf(后半部分拷贝完毕\n);}else{ERR_MSG(fork);return -1;}close(fd_r);close(fd_w);return 0;
} 练习3getpid / getppid
功能获取进程号 、 获取父进程号
原型
#include sys/types.h
#include unistd.h
pid_t getpid(void);
pid_t getppid(void);
返回值
获取进程号 、 获取父进程号
练习4_exit
功能结束进程销毁其在内存中的资源且直接摧毁缓冲区不会刷新缓冲区
原型
#include unistd.h
void _exit(int status);
参数
int status可以传递进程退出状态值给其父进程父进程可以通过wait/ waitpid函数接收。可以传递任意整型;
练习5exit
功能结束进程销毁其在内存中的资源会刷新缓冲区
原型
#include stdlib.h
void exit(int status);
参数
int status可以传递进程退出状态值给其父进程父进程可以通过wait/ waitpid函数接收。可以传递任意整型;
小练1 小练2
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
int main(int argc, const char *argv[])
{pid_t cpid fork();if(cpid 0) //父进程{printf(parent\n);//阻塞函数阻塞等待任意子进程退出pid_t wpid wait(NULL);printf(wpid %d\n,wpid);while(1){ printf(this is parent: %d %d\n,getpid(),cpid);sleep(1);}}else if(0 cpid){int i 0;while(i 3){printf(this id child: %d %d\n,getppid(),getpid());sleep(1);i;}printf(子进程准备退出\n);//_exit(0); //退出进程不会刷新缓冲区exit(0); //退出进程会刷新缓冲区printf(子进程已经退出\n);}else{perror(fork);return -1;}return 0;
}练习6wait
功能1.阻塞函数阻塞等待任意子进程退出 2.回收退出的子进程的资源回收僵尸进程 3.接收子进程退出状态
原型
#include sys/types.h
#include sys/wait.h
pid_t wait(int *wstatus);
参数 int *wstatus接收子进程传递回来的退出状态值若不想接收则填NULL
返回值
0, 成功返回退出的子进程的PID号
-1函数运行失败更新errno;
若没有子进程则wait函数运行失败
父进程只能回收子进程无法回收孙子进程。 注①若子进程退出父进程没有回收子进程的资源此时子进程会变成僵尸进程。 ②没有子进程则wait函数运行失败
练习7子进程退出状态 wait(int* wstatus)中int* wstatus指向的int类型参数只有[8bit, 15bit]用于存储子进程传递的退出状态值。范围为[0, 255]。 所以子进程只能传递256种状态。 1从wstatus中提取子进程退出状态值
int wstatus -1;
pid_t wpid wait(wstatus);
printf(wpid %d wstatus%d\n, wpid, wstatus8);
WEXITSTATUS(wstatus) 提取wstauts中子进程传递的退出状态-- ((status) 0xff00) 8)
2判断子进程是否正常退出
WIFEXITED(wstatus) 若正常退出则返回真。
正常退出 exit _exit 主函数调用return退出。
小练
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
int main(int argc, const char *argv[])
{pid_t cpid fork();if(cpid 0) //父进程{printf(parent\n);//阻塞函数阻塞等待任意子进程退出int wstatus -1;pid_t wpid wait(wstatus);printf(wpid %d wstatus %d\n,wpid,WEXITSTATUS(wstatus));if(WIFEXITED(wstatus))printf(子进程正常退出\n);elseprintf(子进程异常退出\n);while(1){printf(this is parent: %d %d\n,getpid(),cpid);sleep(1);}}else if(0 cpid){int i 0;while(i 3){printf(this is child: %d %d\n,getppid(),getpid());sleep(1);// i;}printf(子进程准备退出\n);//_exit(0); //退出进程不会刷新缓冲区exit(0); //退出进程会刷新缓冲区printf(子进程已经退出\n);} else{perror(fork);return -1;}return 0;
}练习8waitpid
功能阻塞等待指定子进程退出
原型 #include sys/types.h#include sys/wait.hpid_t waitpid(pid_t pid, int *wstatus, int options);
参数 pid_t pid -1 阻塞等待指定进程组下的任意一个子进程退出;-1 阻塞等待当前进程下的任意一个子进程退出 与wait函数的功能基本一致0 阻塞等待当前进程组下的任意一个子进程退出; 0 阻塞等待指定的子进程退出;子进程的pid号 pid参数;int *wstatus接收子进程传递回来的退出状态值若不想接收则填NULLint options 0阻塞方式运行当指定的子进程没有退出的时候该函数阻塞直到指定子进程退出解除阻塞;WNOHANG非阻塞方式运行当指定的子进程没有退出该函数不阻塞立即返回;
返回值 成功0, 成功回收到的子进程的pid号;0, 函数运行成功但是此时子进程没有退出。函数运行失败返回-1更新errno; 1. 若指定的子进程不存在没有子进程的时候函数运行失败;
2. 子进程无法回收父进程的资源
3. 同级之间无法相互回收资源。
小练
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
int main(int argc, const char *argv[])
{pid_t cpid fork();if(cpid 0) //父进程{printf(parent\n);//阻塞函数阻塞等待任意子进程退出,并回收子进程的资源//pid_t wpid waitpid(-1,NULL,0);//非阻塞方式运行若运行到waitpid的时候子进程没有退出则返回0//若运行到waitpid的时候子进程已经退出了则收回尸体并返回子进程的pid号sleep(4);pid_t wpid waitpid(-1,NULL,WNOHANG);printf(wpid %d\n,wpid);while(1){printf(this is parent: %d %d\n,getpid(),cpid);sleep(1);}}else if(0 cpid){int i 0;while(i 3){printf(this is child: %d %d\n,getppid(),getpid());sleep(1);i;} printf(子进程准备退出\n);//_exit(0); //退出进程不会刷新缓冲区exit(0); //退出进程会刷新缓冲区printf(子进程已经退出\n);}else{perror(fork);return -1;}return 0;
} 练习9孤儿进程
父进程退出子进程不退出此时子进程被1号init进程收养变成孤儿进程。
孤儿进程会脱离终端控制且运行在后端不能用ctrlc杀死后端进程但是可以被kill -9杀死。 #include stdio.h#include string.h#include stdlib.h#include head.hint main(int argc, const char *argv[]){//父进程退出子进程不退出pid_t cpid fork();if(cpid 0) //父进程{}else if(0 cpid){while(1){printf(this is child: %d %d\n,getppid(),getpid());sleep(1);}}else{perror(fork);return -1;}return 0;} 练习10僵尸进程
子进程退出父进程不退出去且父进程没有给子进程收尸此时子进程就变成僵尸进程。 注意 僵尸进程只能被回收不能被杀死。僵尸进程有危害占用进程号占用部分内存空间占用物理空间占用进程调度块PCB等等...回收僵尸进程的方式 结合信号的方式回收僵尸进程当子进程退出后通知父进程收尸。wait / waitpid函数回收。缺点阻塞函数父进程无法做自己的事情。非阻塞形式有可能收不到。退出父进程后子进程的资源由内核自动回收。 #include stdio.h#include string.h#include stdlib.h#include head.hint main(int argc, const char *argv[]){//子进程退出父进程不退出pid_t cpid fork();if(cpid 0) //父进程{while(1){printf(this is parent: %d %d\n,getpid(),cpid);sleep(1);}}else if(0 cpid){}else{perror(fork);return -1;}return 0;} 练习11守护进程幽灵进程
1.守护进程脱离于终端且运行在后端。
2.守护进程在执行过程中不会将信息显示在任何终端上避免影响前端任务执行。且不会被任何终端产生的终端信息所打断。
3.守护进程目的需要周期性执行某个任务或者周期性等待处理某些事情的时候为了避免影响前端执行或者被前端信息打断的时候可以使用守护进程。 守护进程的创建 1.创建孤儿进程所有工作都在子进程中执行从形式上脱离终端控制。 fork(), 退出父进程 2.创建新的会话组使子进程完全独立出来防止兄弟进程对其有影响 setsid() 函数
功能创建一个新的进程组和会话组成为该进程组和会话组组长
原型#include sys/types.h#include unistd.hpid_t setsid(void); 3.修改当前孤儿进程的运行目录为不可卸载的文件系统例如根目录/tmp 防止运行目录被删除后导致进程崩溃 chdir函数
功能修改运行目录;
原型#include unistd.hint chdir(const char *path);
chdir(/); 注意从当前位置往后运行在指定的目录下 4.重设文件权限掩码umask(0), 一般清零 5.关闭所有文件描述符从父进程继承过来的文件描述符不会用到浪费资源。 #include stdio.h
#include string.h
#include stdlib.h
#include head.h
int main(int argc, const char *argv[])
{//创建孤儿进程pid_t cpid fork();if(0 cpid){//创建新的会话pid_t sid setsid();printf(sid %d\n, sid);//修改运行目录为不可卸载的文件目录下chdir(/);//清空文件权限掩码umask(0);//关闭所有文件描述符for(int i 0; igetdtablesize(); i) close(i);while(1){ //守护进程运行的周期性代码sleep(1);}}return 0;
}三、课后作业
1.打印时钟在终端上若终端输入quit结束时钟
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
int main(int argc, const char *argv[])
{pid_t cpid fork();if(cpid 0){time_t t;struct tm *infoNULL;while(1){if(waitpid(-1,NULL,WNOHANG) 0)break;t time(NULL);info localtime(t);printf(%d-%02d-%02d %02d:%02d:%02d\r,\info-tm_year1900,info-tm_mon1,\info-tm_mday,info-tm_hour,info-tm_min,info-tm_sec);fflush(stdout);sleep(1);}}else if(0 cpid){char str[10];while(1){ scanf(%s,str);if(0 strcmp(str,quit))exit(0);sleep(1);}}return 0;
}