定义:进程是一个具有一定独立功能的程序的一次运行活动,同时也是资源分配的最小单元;
进程与程序的区别:
进程是动态的,程序是静态的:程序是有序代码的集合;进程是程序的执行。通常进程不可在计算机之间迁移;而程序通常对应着文件、静态和可以复制
进程是暂时的,程序使长久的:进程是一个状态变化的过程,程序可长久保存
进程与程序组成不同:进程的组成包括程序、数据和进程控制块(即进程状态信息)
进程与程序的对应关系:通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。
进程的状态:
执行状态:进程正在占用CPU
就绪状态:进程已具备一切条件,正在等待分配CPU的处理时间片
等待状态:进程不能使用CPU,若等待事件发生则可将其唤醒
1.创建一个进程:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
pid = fork();//创建一个进程,一般有三种返回值
if(-1 == pid)
{
perror("fork");
exit(1);
}
else if(0 == pid)//子进程创建成功,子进程和父进程同时进行,先后顺序不一定
{
printf("This is child! pid: %d\n", getpid());//getpid()获取进程号
printf("ppid: %d\n", getppid());//getppid()获取父进程的进程号
}
else//父进程返回子进程的进程号
{
printf("This is parent! pid %d\n", getpid());
printf("pid : %d\n", pid);//返回子进程的进程号
}
return 0;
}
2.fork()创建一个子进程的时候,写实拷贝父进程的内存空间,即一个G的内核空间,3个G 的用户空间
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int a = 0;
pid = fork();
if(-1 == pid)
{
perror("fork");
exit(1);
}
else if(0 == pid)
{
a++;
printf("child a:%d, %p", a, &a);//输出a=1
}
else
{
a++;
printf("parent a:%d, %p", a, &a);//输出a=1
}
//两个a的地址相同,子进程写时拷贝父进程的内存空间,两个a是不同的a
return 0;
}
3.实现子进程写,父进程读
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main()
{
pid_t pid;
int fd, ret;
char buf[32] = {0};
fd = open("hello.txt", O_CREAT | O_RDWR | O_EXCL, 00700);//创建并打开一个文件
pid = fork();
if(-1 == pid)
{
perror("fork");
exit(1);
}
else if(0 == pid)
{
scanf("%s", buf);
ret = write(fd, buf, strlen(buf));
if(-1 == ret)
{
perror("write");
exit(1);
}
}
else
{
sleep(5);//子进程和父进程是并发执行的,scanf还没输入完父进程已经结束了,所以要睡眠几秒
lseek(fd, 0, SEEK_SET);
memset(buf, 0, sizeof(buf));
ret = read(fd, buf, sizeof(buf));//此时buf已经清空了,所以不能用strlen
if(-1 == ret)
{
perror("read");
exit(1);
}
}
return 0;
}
4.回收子进程wait()
孤儿进程:子进程还没结束,父进程先结束了
僵尸进程:父进程没有回收子进程的资源
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
pid = fork();
if(-1 == pid)
{
perror("fork");
exit(1);
}
else if(0 == pid)
{
printf("child\n");
}
else
{
printf("parent!\n");
int status;
wait(&status);//1.等待子进程结束 2.回收子进程的资源
//waitpid(pid, &status, 0);
}
return 0;
}
5.创建子进程的另一种方法vfork()
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int a = 0;
pid = vfork();
if(-1 == pid)
{
perror("vfork");
exit(1);
}
else if(0 == pid)//此时一定是子进程先运行完再运行父进程
{
a++;
printf("This is child! a: %d, %p\n", a, &a);
sleep(2);
exit(1);//此时一定要指明退出状态
}
else
{
a++;
printf("This is parent! a: %d, %p\n", a, &a);
}
//此时两个a的值不同,地址也相同,因为vfork()创建的子进程和父进程共享内存空间
return 0;
}
6.execl()函数
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
pid = fork();
if(-1 == pid)
{
perror("fork");
exit(1);
}
else if(0 == pid)
{
printf("This is child!\n");
execl("/bin/ls", "-a", "-l", NULL);//调用另一个进程ls
}
else
{
printf("This is parent!\n");
}
return 0;
}
7.信号的使用
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <signal.h>
void handlder(int sig)
{
printf("hello %d\n", sig);//sig代表的是SIGINT 宏定义为2
}
int main()
{
//signal(SIGINT, SIG_IGN);//忽视Ctrl C
signal(SIGINT, handlder);//handlfer是一个函数指针
while(1);
return 0;
}
//闹钟信号
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <signal.h>
void handlder(int sig)
{
printf("hello\n");
alarm(1);
}
int main()
{
alarm(1);//1s后给进程发送SIGALRM信号,有效期一次
signal(SIGALRM, handlder);
while(1);//进程不能结束
return 0;
}