每个线程一个栈,每个进程一个堆,malloc申请的是堆
善用man手册,例如man pthread_cancel
进程
进程的含义
进程能打开文件个数1024;栈的大小8M(8兆)
PCB块:进程控制块
系统中只有一个cpu,通过对cpu的调度,作用于每一个pcb,进程控制块(进程所有相关控制信息都在pcb里面放着),实现对每一个程序的运行(并发的)。
并发:可以运行多次
进程和程序的区别
code:代码段(只能被读,不能写)
data:数据段(变量)
heap:堆(开始:malloc,结束:free)
share/map:共享区/映射区(把库函数的函数映射过来)
stack:栈区(8M)(参数,局部变量,返回值都在这里)
linux的进程状态图如图:
进程的作用,状态等
显示所有进程:
默认是15也是关闭的意思
kill -9 pid号 强制关闭进程
fork
一般来说子的pid号略大于父的
fork简单示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
while(1)
{
printf("fahter, 发送视频\n");
sleep(1);
}
}
else if(0 == pid)
{
while(1)
{
printf("child, 接收控制\n");
sleep(1);
}
}
else
{
perror("fork");
return 1;
}
return 0;
}
结果为
CPU的调度是随机的,父和子谁走不一定,但是一定是同时走的
变量不共享代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int a = 10;
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
sleep(3);
printf("father a is %d\n",a);
}
else if(0 == pid)
{
a+=20;
printf("child a is %d\n",a);
}
else
{
perror("fork");
return 1;
}
printf("a is %d\n",a);
return 0;
}
结果为:
互不影响
getpid
getpid用法
执行多个程序:子进程
父进程中括号里的pid拿的是子的id号,子进程仅仅代表是子进程并不代表子的id号为0
需要几个子就fork(n)
子认识父,但是父要想认识子只能在第一句里面得到子的id号
getpid和getppid的用法
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int a = 10;
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
sleep(3);
printf("father a is %d, pid:%d ppid:%d\n",a,getpid(),getppid());
}
else if(0 == pid)
{
a+=20;
printf("child a is %d pid:%d ,ppid:%d\n",a,getpid(),getppid());
}
else
{
perror("fork");
return 1;
}
printf("a is %d, pid:%d ppid:%d\n",a,getpid(),getppid());
return 0;
}
结果为:
(因为变量不共享)
练习:注意截断特性(至少3个,至多8个)
fork()&&fork()||fork()
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
fork()&&fork()||fork();
printf("pid :%d\n",getpid());
return 0;
}
结果为:五个进程,对应五个pid号
父子进程的关系
父子进程代码段是共享的
通过指针指向code段,因为复制过去其他都要改变,只有code段不变
进程终止的情况
IO的清理工作包括:缓冲区在linux里面,A.out运行完,数据会进入缓冲区,达到一定条件,才能显示到屏幕上,然后关闭文件,关闭流指针。(回收!!!)
exit用法
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("hello");
exit(0);
printf("aaaa\n");
return 0;
}
exit(0);表示程序正常结束
exit(1);表示程序有错误或者exit(-1);
结果为:后面的aaaa没有显示出来,因为exit让进程结束了已经
_exit用法
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("hello");
_exit(0);
printf("aaaa\n");
return 0;
}
结果为:啥也没打印出来,因为没执行清理函数,不走缓冲区了,缓冲区的数据直接就被扔了,所以啥也不显示
行缓冲是printf后面有\n
全缓冲是fputs对文件的操作
fflush是当前三种都不满足,但还是想在屏幕上看到printf的内容,就写fflush(stdout)
stdout是相对计算机而言的,对于计算机来说就是输出
四个条件只需满足一个就可以
僵尸进程和孤儿进程的定义
进程的退出
回收是父进程回收,孤儿进程的时候父都没了,所以不回收,就不管了
organ.c孤儿进程代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
printf("father pid:%d ppid:%d\n",getpid(),getppid());
exit(0);//正常结束了
}
else if(0 == pid)
{
sleep(3);
printf("child pid:%d ppid:%d\n",getpid(),getppid());
}
else
{
perror("fork");
return 1;
}
return 0;
}
结果:
子的ppid(父进程id)已经不是上一行的34807了,因为父已经消亡了
zombie.c 僵尸进程代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
printf("father pid:%d ppid:%d\n",getpid(),getppid());
sleep(10);
}
else if(0 == pid)
{
printf("child pid:%d ppid:%d\n",getpid(),getppid());
exit(0);//子消亡
}
else
{
perror("fork");
return 1;
}
return 0;
}
结果为:
用top命令看
0变1
父结束的时候看看有没有已经结束的子,有的话就将子回收,然后自己再退出
子的pid一般比父大1
作业:创建n个进程
num_proc.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
int n =3;
int i = 0 ;
for(i=0;i<n;i++)
{
pid_t pid = fork();
if(pid>0)
{
continue;
}
else if(0 == pid)
{
printf("child, pid:%d ppid:%d\n",getpid(),getppid());
exit(0);
}
else
{
perror("fork");
return 1;
}
}
printf("father pid:%d, ppid:%d\n",getpid(),getppid());
return 0;
}
结果:一父三子
作业:统计进程的个数
count_process.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <dirent.h>
int do_count()
{
DIR* dir = opendir("/proc");
if(NULL == dir)
{
perror("opendir");
exit(1);
}
int num=0;
while(1)
{
struct dirent* info = readdir(dir);
if(NULL == info)
{
break;
}
if(DT_DIR == info->d_type )//判断它是不是目录
{
if(info->d_name[0]>'0' && info->d_name[0]<'9')//判断第一个字符是不是数字
{
num++;
}
}
else
{
continue;//啥也不是,就读下一个
}
}
closedir(dir);
return num;
}
int main(int argc, char *argv[])
{
FILE* fp = fopen("1.txt","w");
if(NULL == fp)
{
perror("fopen");
exit(1);
}
time_t tm;
int n = 3;
pid_t pid = fork();
if(pid>0)
{
while(n--)
{
int num=do_count();
time(&tm);
fprintf(fp,"father %d %d %s",getpid(),num,ctime(&tm));
fflush(fp);
sleep(3);
}
}
else if(0 == pid)
{
while(n--)
{
int num=do_count();
time(&tm);
fprintf(fp,"child %d %d %s",getpid(),num,ctime(&tm));
fflush(fp);
sleep(5);
}
}
else
{
perror("fork");
return 1;
}
fclose(fp);
return 0;
}
结果:
注意:僵尸进程产生要回收,父对子回收
补充一个不是很重要的函数:回调函数atexit
atexit.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
char * tmp=NULL;
void clean(void)//clean是指针函数,这个是进程退出前来调用的
{
printf("this is clean %s\n",tmp);
free(tmp);
}
int main(int argc, char *argv[])
{
atexit(clean);
tmp =(char*) malloc(50);//malloc回来的是void*,要强转
strcpy(tmp,"hello");
printf("123123\n");
return 0;
}
进程的回收(针对于僵尸进程)wait
wait一次只能回收一个,不关心状态括号里写NULL
如果子还没有结束,不能回收,这个时候就进入阻塞状态,父就卡在那不走了,直到有子进程消亡,才能回收
比如说:父同时有两件事,一个是回收,一个是输出,如果阻塞了,那就卡住了,也不会输出也不会回收
wait.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
printf("father pid:%d ppid:%d\n",getpid(),getppid());
pid_t recycle_pid = wait(NULL);?//验证wait有阻塞功能
printf("recycle pid %d\n",recycle_pid);
sleep(10);
printf("aaa\n");
}
else if(0 == pid)
{
sleep(3);
printf("child pid:%d ppid:%d\n",getpid(),getppid());
exit(0);
}
else
{
perror("fork");
return 1;
}
return 0;
}
结果为:
进阶版本
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
//stat("1.txt",&st);