一、什么是进程
(一)进程的含义?
进程是一个程序执行的过程,会去分配内存资源,cpu的调度
(二)进程分类:
1、交互式进程
2、批处理进程 shell脚本
3、 守护进程
(三)进程与程序的区别
1)程序是永存,进程是暂时的
2)进程有程序状态的变化,程序没有
3)进程可以并发,程序无并发
4)进程与进程会存在竞争计算机的资源
5)一个程序可以运行多次,变成多个进程
一个进程可以运行一个或多个程序
(四)进程的作用:
并发并行(各执行各的)
(五)进程的状态:
3个状态,就绪→执行态→阻塞(等待,睡眠)基本操作系统
linux中的状态,运行态,睡眠态,僵尸态,暂停态。

(1)运行态(running):进程占有处理器正在运行。
(2)就绪态(ready):进程具备运行条件,等待系统分配处理器以便运行。
(3)阻塞态(blocked):又称为或睡眠(sleep)态,指进程不具备运行条件,正在等待某个事件的完成。
(4)僵尸态(zombie):子运行完,父没运行完,子进程会以终止状态保持在进程表中,并且会一直在等待父进程读取才能退出。
(5)孤儿态:父运行完,子没运行完,子处于托管状态,加重系统负担
(6)创建态:进程正在被创建,但尚未转到就绪态。
(7)终止态:进程已经完成执行并准备被撤销。
cpp
进程的状态:
PROCESS STATE CODES
Here are the different values that the s, stat and state output specifiers
(header "STAT" or "S") will display to describe the state of a process:
D uninterruptible sleep (usually IO) //不可中断的睡眠态
R running or runnable (on run queue) // 运行态
S interruptible sleep (waiting for an event to complete)//可中断的睡眠态
T stopped by job control signal // 暂停态
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group
R --- 运行态
D --- 不可中断 睡眠态
S --- 可中断 睡眠态
T --- 暂停态
Z --- 僵尸态
cpp
cb
struct task_struct {
PID, //进程标识符
PPID, //父进程ID号 parent
当前工作路径 //chdir
umask //0002
进程打开的文件列表 //文件IO中有提到
信号相关设置 //处理异步io, ---段错误
用户id,组id
进程资源的上限
}
二、进程管理的命令
1、top //类似Windows的下任务管理器
2、ps -eLf | head -1 //可以观察到 PID PPID
3、ps -eLf | grep a.out //查看a.out 信息 //可以观察到 PID PPID
4、ps -aux | grep a.out //可以查看进程 的状态
5、pstree //进程树
6、pstree -sp pid号 //查看指定的进程的关系
7、kill //给进程发信号 //kill -l //查看可以发送的信号
操作:
将子进程杀死 。结束子进程,父进程还在,但是父进程并没有对子进程"收尸"

操作:
将父进程杀死 。子进程 还在 ,父进程不在 ---- 孤儿进程
---- 此时由init进程 收养

特殊:
孤儿进程
子进程 还在,父进程不在
僵尸进程
子进程 结束,父进程还在,且父进程并未"收尸"
僵尸态进程有危害
三、函数
pid_t fork(void);
功能:
创建子进程 (通过复制调用进程)
参数:
void
返回值:
成功
在父进程中 返回子进程的pid号
在子进程中 返回0
失败
-1 && errno 被设置
pid号:
pid 本质上就是一个数值
正整数 1
cpp
#include<stdio.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
pid_t pid = fork();
if(pid<0)
{
perror("fork fail");
return -1;
}
while(1)
{
if(pid > 0)
{
printf("hello\n");
}else if(pid ==0)
{
printf("world\n");
}
}
return 0;
}
1、子进程先运行和是父进程先进程,顺序不确定。
变量不共享。
2、子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。
3、此时,父子进程各自拥有独立的4g内存空间 (32位的系统)
4、功能
通过该函数可以从当前进程中克隆一个同名新进程。
克隆的进程称为子进程,原有的进程称为 父进程。
子进程是父进程的完全拷贝。
复制之后,
子进程和父进程 各自拥有自己的 用户空间(进程空间)
子进程和父进程的执行过程是从fork函数之后执行。
子进程与父进程具有相同的代码逻辑。
5、返回值:int 类型的数字。
在父进程中:成功 返回值是子进程的pid号 >0
失败 返回-1;
在子进程中:成功 返回值 0
失败 无
6、注意:
1.创建好之后,父子进程的运行顺序是不确定 ---全部取决于 操作系统的调度
注意:
1.父子进程创建好之后,各自拥有独立4G内存空间(32位系统)
2.他们的数据相互独立,父进程或子进程对数据的修改,不会相互影响,只会对各自造成影响
(一)、练习
如果两次fork同时前后执行,会生成几个进程?
fork();
fork();
他们之间的关系如何表示,
有多少个子进程,
有没有孙进程?
2、fork()&&fork()||fork(); //总共几个进程
cpp
#include<stdio.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
fork()&&fork()||fork();
while(1);
sleep(1);
return 0;
}


3、练习:
自己分别定义一个 static的变量 static int a = 0;
全局变量 int b = 1;
堆区 int *p = (int *)malloc(sizeof(int));
*p = 2;
(做修改)父进程中 做加1的操作 ,
子进程中做加2的操作
sleep(1);
分别打印,查看效果!
cpp
#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
pid_t pid = fork();
static int a =0;
int b = 1;
int *p = (int *)malloc(sizeof(int));
*p = 2;
while(1)
{
if(pid > 0)
{
a++;
b++;
*p++;
sleep(1);
printf("father ");
printf("a = %d b = %d *p = %d\n",a,b,*p);
}else if(pid == 0)
{
a+=2;
b+=2;
*p+=2;
printf("sun ");
printf("a = %d b = %d *p = %d\n",a,b,*p);
sleep(1);
}
}
return 0;
}

4、创建n个进程 :
输入n 创建n个子进程
cpp
#include<stdio.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
int n = 0;
scanf("%d",&n);
int i = 0;
pid_t pid = 0;
for(i = 0;i < n;i++)
{
pid = fork();
if(pid < 0)
{
perror("fork fail");
return -1;
}
if(pid>0)
{
continue;
}else if(pid == 0)
{
break;
}
}
while(1)
sleep(1);
return 0;
}
5、创建n个进程,分批复制文件
cpp
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
void do_copy(int fd_s,int fd_d,int size,int i,int length)
{
char buf[1024];
//定位到要操作位置
lseek(fd_s,i*size,SEEK_SET);
lseek(fd_d,i*size,SEEK_SET);
int ret = read(fd_s,buf,length);
write(fd_d,buf,ret);
}
int main(int argc, const char *argv[])
{
if (argc != 3)
{
printf("Usage: %s <src> <dest>\n",argv[0]);
return -1;
}
int n = 0;
printf("Input proccess num:");
scanf("%d",&n);
int i = 0;
pid_t pid = 0;
for (i = 0; i < n;++i)
{
pid = fork();
if (pid < 0)
{
perror("fork fail");
return -1;
}
if (pid > 0)
{
continue;
}else if (pid == 0)
{
break;
}
}
if (pid > 0)
{
printf("father exit!\n");
return 0;
}else if (pid == 0)
{
int fd_s = open(argv[1],O_RDONLY);
if (fd_s < 0)
{
perror("open fail");
return -1;
}
int fd_d = open(argv[2],O_WRONLY|O_CREAT|O_EXCL,0666);
if (fd_d < 0)
{
if (errno == EEXIST)
{
fd_d = open(argv[2],O_WRONLY);
}else
{
perror("open fail");
return -1;
}
}
struct stat st;
if (stat(argv[1],&st) < 0)
{
perror("stat fail");
return -1;
}
printf("size = %ld\n",st.st_size);
int size = st.st_size/n;
int length = size;
if (i == n-1)
{
length = st.st_size - size*(n-1);
}
printf("i = %d each size = %d\n",i,size);
do_copy(fd_s,fd_d,size,i,length);
close(fd_s);
close(fd_d);
}
return 0;
}