1、什么是进程?区分程序
进程是指程序执行的可执行文件;而程序是存放到磁盘的可执行文件;
2、进程的一些特性:
(1)动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
(2)并发性:任何进程都可以同其他进程一起并发执行
(3)独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
(4)异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
(5)结构特征:进程由程序、数据和进程控制块三部分组成.
3、进程互斥:
(1)、概念:进程互斥是指当有若干进程都要使用某一共享资源时,任何时候最多允许一个进程使用,其他要使用该资源的进程必须等待,直到占用该资源者释放了该资源为止。
(2)、例如:车站的买票窗口,假如现在总共有十张编号座位号的票,现在有两个窗口都开着一起 卖这十张票,此时编号为1 的票开始出票,两个窗口都在卖这张,编号1的就一张,他只允许被一个窗口售卖(被一个进程占用),这时候就产生了进程的互斥;
(3)、临界资源:这样的车票就被称为临界资源(操作系统中将一次只允许一个进程访问的资源称为临界资源)
(4)、临界区:进程中访问临界资源的那段程序代码称为临界区
还拿上面的卖票,我们知道的在实际卖票的过程中,同一张票不可能卖两次,具有唯一编号的票只能被买一次,这就是因为买票系统有自己的临界区,他里边有程序来保证每张票在同一时刻只会被一个窗口售卖(也就是纸杯一个进程占用);
抢锁、上锁—->取票——>票数减1—–>开锁;
也就是两个进程竞争抢占这个资源,抢到之后上锁,其他进程都是进不来,你在里边占用这个资源,也就是取票,占用结束之后,开锁,这时候想要抢占资源的进程又可以重新抢锁;这个过程编码实现后就是临界区;
4、进程id:
每个进程都有一个ID(ID是一个正整数),唯一标识了系统中的这个进程。
每个进程都有一个创建它的进程,叫父进程(Parent Process);
进程ID(PID):标识进程的唯一数字;
父进程ID(PPID);
启动进程的用户ID(UID);
5、获取进程id的函数getpid:
(1)获取本进程ID
pid_t getpid(void)
(2)获取父进程ID
pid_t getppid(void)
(3)例子代码:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
printf ("当前进程 Id: %d\n", getpid());
printf ("当前父进程Id: %d\n", getppid());
printf ("当前用户 Id: %d\n", getuid());
while (1);
return 0;
}
6、进程创建fork
(1)、当fork()顺利完成任务时,就会存在两个进程,每个进程都从fork()返回处开始继续执行。
(2)他俩只会共享代码段,子进程的数据段,堆,栈都是copy了一份父进程的,不共享;
(3)不能确定那一个进程先执行;
(4)创建进程代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
//pid_t fork(void);
int main()
{
pid_t pid = fork(); //如果你创建成功有两个返回值,一个0代表子进程返回值,一个大于0的数字,是父进程返回的子进程的id号;
if(pid == -1) //-1表示创建失败;
{
printf("创建子进程失败了\n");
}
else if(pid > 0)
{
printf("我是父亲进程: %d\n",getpid());
}
else (pid == 0)
{
printf("我是子进程:%d\n",getpid());
}
return 0;
}
(5)体现不共享数据段的代码:
int main()
{
int count = 0;
pid_t pid = fork();
//创建子进程后会有两个进程跑这段代码,会有两个打印,值都是1,说明两个进程跑的时候count初始值都是0;并没有共享数据段,一个程序跑完后加一,另一个程序接着在前一个程序的数据基础上再加一;
count++;
Printf(“%d\n”,count);
Return 0;
}
7、exec函数(execl,execlp,execv,sysytem)
(1)exec用被执行的程序替换调用它的程序
从替换调用他的程序代码这一方面来说下面三个是属于一类
Execl:int execl(const char * path, const char* arg1,…)
Execlp:int execlp(const char * path, const char* arg1,…)
Execv:int execv(const char path, const char argv[])//可执行程序存进字符串指针数组,和上面两个没有本质区别
Execl替换例子代码:
int main12()
{
int ret = execl("/bin/ls", "ls" ,NULL);//这个execl创建的新的进程替换了原有的代码段;ls是存在于linux中bin目录下的可执行文件,功能展示当前所在目录的文件;
if (ret == -1)
{
return -1;
}
printf("aaaaaaaaaaaa\n"); //打印的这一段代码已经被替换,不会有输出;
return 0;
}
(2)区别于fork:
fork 创建一个新的进程,产生一个新的PID
exec 启动一个新程序,替换原有的进程,因此进程的PID不会改变。
(3)System
格式:int system(const char* string)
这个好,这个不会替换调用他的函数的代码;调用fork产生子进程,由子进程来调用 /bin/sh -c string来执行参数string所代表的命令,这个调用起来真的是超级方便,不用像exec那么多的参数;
看代码:
int main7()
{
printf("aaaaaaaaaaaaaaaaaa\n");
system("clear");
sleep(1);
system("ls");
printf("aaaaaaaaaaaaaaaaaaccccccc\n");
return 0;
}