寒假学习 第15天 (linux 高级编程) 笔记 总结
接着昨天
(1) int system(const char *command);
(2) FILE *popen(const char *command, const char *type);
(3) exec系列函数
int execl( const char *path, const char *arg, ...);
//第一个参数:替换的进程,第二个参数..... 命令行
//命令行格式:命令名 选项参数 并且命令行必须、以0结尾
int execlp( const char *file, const char *arg, ...);
int execle( const char *path, const char *arg , ..., char * const envp[]);
int execv( const char *path, char *const argv[]);
int execvp( const char *file, char *const argv[]);
替换当前进程的代码空间的代码数据,函数本生不会创建进程 见例子1
execl与execlp的区别
execl必须是绝对路径,execlp不用 见例子2
例子1:
test.c
#include
#include
int main(int argc, const char *argv[])
{
printf("%d\n",getpid());
sleep(5);
return 0;
}
#include
#include
int main(int argc, const char *argv[])
{
printf("%d\n",getpid());
int r=execl("test","mytest",NULL);//结尾必须是0
printf("end %d\n",r);
return 0;
}
运行时 printf(“end %d\n”,r); 不会执行
并且打印的两个pid相同
例子2:
#include
#include
int main(int argc, const char *argv[])
{
printf("%d\n",getpid());
int r=execl("/bin/ls","ls","-l",NULL);
printf("end %d\n",r);
return 0;
}
1. 克隆父进程的代码跟执行位置,重fork开始就分两个进程进行,例子1
2. fork创建的进程,父子进程是同时进行的
子进程创建好了以后,父进程马上把时间片交给系统,然后系统在调度下一个时间片由那个执行。 例子2
#include
#include
int main(int argc, const char *argv[])
{
printf("before creat process!\n");
int pid=fork();
printf("after creat process:%d\n",pid);
return 0;
}
结果:
before creat process!
after creat process:2651
after creat process:0 //为什么为0?因为fork不光克隆父进程的代码,还克隆了父进程的执行位置,所以子进程中pid=fork() 是没有执行的,pid为0.
#include
#include
int main(int argc, const char *argv[])
{
printf("before creat process!\n");
int pid=fork();
while(1)
{
if(pid==0){
printf("AAAAA\n");
sleep(1);
}else{
printf("BBBBB\n");
sleep(1);
}
}
return 0;
}
结果:AAAAA 跟BBBBB交叉出现
1. fork 的用处? 使用fork实现多任务(Unix本身是不支持多线程,有时就要用fork创建多进程)
2. 实现多任务的方式
1.线程
2.进程
3.信号
4.异步
5.进程池与线程池
例子:使用进程创建多任务(让屏幕同时显示时间跟随机数)#include
#include
#include
#include
WINDOW *wtime,*wnumb;
int main(int argc, const char *argv[])
{
initscr();
box(stdscr,0,0);
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()){ //父进程
time_t tt;
struct tm *t;
while(1)
{
tt=time(0);
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{ //子进程
while(1){
mvwprintw(wnumb,1,1,"%8d",rand()%100000000);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
usleep(100000);
}
}
endwin();
return 0;
}
是独立的两个进程,有各自的pid
从进程树可以看出两个独立但不平行是父子节点关系(pstree可以查看进程树)
子进程就依托根进程init (孤儿进程)
理论上孤儿进程对系统没有任何的危害。
子进程先结束
子进程会成为僵尸进程。
僵尸进程不占用内存,CPU但在我们的进程任务管理树上占用一个节点。
僵尸进程会造成进程名额资源的浪费,所以要处理僵尸进程
例子:
#include
#include
#include
int main(int argc, const char *argv[])
{
if(fork()){
int status;
printf("parent\n");
wait(&status);
printf("%d\n",WEXITSTATUS(status));
sleep(1000);
}else{
printf("child\n");
sleep(10);
exit(34);
}
return 0;
}
运行10秒后 子进程回收,不会变成僵尸进程,pstree查看看不到子进程
子进程结束通常会向父进程发送 一个SIGCHLD信号(kill -l 可以查看所有信号)
signal(int sig,void(*fun)(int));
向系统注册:告诉系统只要sig信号发生,系统就停止进程,并调用fun函数。
当函数执行完毕,继续原来的进程 (中断)
1 实现处理函数
2使用signal来绑定信号与函数
例子:僵尸进程回收
#include
#include
#include
void deal(int s)
{
int status;
wait(&status);
printf("回收中!...\n"); //这个函数不执行完毕程序就不会进行下去
sleep(10);
printf("回收完毕:%d\n",WEXITSTATUS(status));
}
int main(int argc, const char *argv[])
{
if(fork()){
signal(17,deal); //向系统注册 SIGCHLD 就是 17
while(1)
{
printf("parent\n");
sleep(1);
}
}else{
printf("child\n");
sleep(10);
printf("child out\n");
exit(34);
}
return 0;
}
#include
#include
int main(int argc, const char *argv[])
{
int a = 20;
if(fork()){
printf("patent a:%d\n",a);
printf("patent a:%p\n",&a);
a=33;
sleep(3);
}else{
printf("child a:%d\n",a);
printf("child a:%p\n",&a);
sleep(2);
printf("child a:%d\n",a);
printf("child a:%p\n",&a);
}
return 0;
}
结果:
patent a:20
patent a:0x7fffbd3e533c
child a:20
child a:0x7fffbd3e533c
child a:20
child a:0x7fffbd3e533c
#include
#include
int main(int argc, const char *argv[])
{
int *a = (int *)malloc(4);
*a = 20;
if(fork()){
printf("patent a:%d\n",*a);
printf("patent a:%p\n",a);
a=33;
sleep(3);
}else{
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
sleep(2);
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
}
return 0;
}
结果:
patent a:20
patent a:0x1d2f010
child a:20
child a:0x1d2f010
child a:20
child a:0x1d2f010
#include
#include
#include
int main(int argc, const char *argv[])
{
int *a = (int *)mmap(0,4,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,0,0);
*a = 20;
if(fork()){
printf("patent a:%d\n",*a);
printf("patent a:%p\n",a);
*a = 33;
sleep(3);
}else{
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
sleep(2);
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
}
return 0;
}
结果:
patent a:20
patent a:0x7f76f73f1000
child a:20
child a:0x7f76f73f1000
child a:33 //改变了,
child a:0x7f76f73f1000
#include
#include
#include
int main(int argc, const char *argv[])
{ //跟上面的例子的区别只是把PROT_SHARE 改成MAP_PRIVATE
int *a = (int *)mmap(0,4,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,0,0);
*a = 20;
if(fork()){
printf("patent a:%d\n",*a);
printf("patent a:%p\n",a);
*a = 33;
sleep(3);
}else{
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
sleep(2);
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
}
return 0;
}
结果:
patent a:20
patent a:0x7fe9bb8ab000
child a:20
child a:0x7fe9bb8ab000
child a:20 //没有改变
child a:0x7fe9bb8ab000
映射内存
#include
#include
#include
int main(int argc, const char *argv[])
{
int *a=sbrk(4);
*a = 20;
if(fork()){
printf("patent a:%d\n",*a);
printf("patent a:%p\n",a);
*a = 33;
sleep(3);
}else{
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
sleep(2);
printf("child a:%d\n",*a);
printf("child a:%p\n",a);
}
return 0;
}
结果:
patent a:20
patent a:0x12a1000
child a:20
child a:0x12a1000
child a:20
child a:0x12a1000
#include
#include
int main(int argc, const char *argv[])
{
int fd=open("test.txt",O_RDWR);
if(fork()){
printf("patent\n");
char buf[1024]={0};
read(fd,buf,1024);
printf("%s\n",buf);
}else{
printf("child\n");
char buf[1024]={0};
read(fd,buf,1024);
printf("%s\n",buf);
}
close(fd);
return 0;
}
test.txt 内容
123456
结果:
patent
123456
child
#include
#include
int main(int argc, const char *argv[])
{
int fd=open("test.txt",O_RDWR);
if(fork()){
printf("patent\n");
char buf[1024]={0};
lseek(fd,0,SEEK_SET);
read(fd,buf,1024);
printf("%s\n",buf);
}else{
printf("child\n");
char buf[1024]={0};
lseek(fd,0,SEEK_SET);
read(fd,buf,1024);
printf("%s\n",buf);
}
close(fd);
return 0;
}
结果:
patent
123456
child
123456
#include
#include
#include
#include
main()
{
int fd=open("test.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
if(fork())
{
write(fd,"Hello",5);
close(fd);
}else{
write(fd,"Word",5);
close(fd);
}
}
cat test.txt结果:
HelloWord
#include
#include
#include
#include
main()
{
if(fork())
{
int fd=open("test.txt",O_RDWR);
write(fd,"Hello",5);
close(fd);
}else{
int fd=open("test.txt",O_RDWR);
write(fd,"Word",5);
close(fd);
}
}
cat test.txt 结果:
Word