前言:周末起来打开手机,开启一天的冲浪生活,等了一夜的女神聊天框只有一个晚安;于是你点开美团决定给她送点吃的,一会之后外卖小哥问你是不是点错了,对面是个男的。是啊,人类社会总是充满了不确定,明天说不定就中彩票了~
计算机就不一样,因为它充满了BUG…
1. 什么是进程
字面意义:正在进行的一个过程。
哈哈,是不是很简单,就像吃饭一样,你是执行这个进程动作的机器;转换视角到计算机则变成了CPU是一个进程的执行者~
show code!
(Linux通过以下指令可以进行当前系统进程打印)
ps axu
笔者机器运行部分结果
看起来很不知所云对不对?但是就是这些进程和OS一起撑起了软件世界的精彩!现在不理解没关系,慢慢来,笔者会慢慢带大家了解这个世界的!
2. Linux第一个进程
通过上面的shell指令我们可以了解到,Linux系统上运行着各种各样的进程,面对这些形形色色的进程我们忍不住问出那个灵魂问题:谁是第一个进程?
也许有信仰上帝的人会说:Computer God.
也许有信仰马圣的人会说:第一个物质进程.
。。。。。。
不卖关子了,其实,Linux第一个进程很佛系, 称IDLE(不是Python那个开发环境哈),真正的0号,
当它被内核运行之后,它也非常符合名字(懒)的直接放权让init进程去干活了(具体的活暂不展开)~
然后就是道教有名的道生一,一生万物理论(老子要是现代人估计是个计算机进程领域大拿)
Linux进程按照上面的描述形式就形成了一颗进程树
3. 向传统C程序 say byebye
理论聊了半天,应该上正菜了:写一个简单的多进程程序!
先看今天的食材:
#include <unistd.h>
pid_t fork( void);
fork系统调用用于创建一个新进程,称为子进程,它与原进程(称为系统调用fork的进程)同时运行,此进程称为父进程。
#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
execve函数可以使进程能够以全新程序来替换当前运行的程序。再次过程中,将丢弃旧有程序,进程的栈.数据以及堆段会被新程序所替换。
4. 生子当如parent – fork
一个进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次(唯一区别是子进程中返回0,父进程中返回子进程ID),事情开始魔幻了~
通过fork的子进程是父进程的副本,BUT,父子进程间不共享这些存储空间。
第一个简单的程序
#include <stdio.h>
#include <unistd.h>
static int s_val = 0;
int main()
{
int pid = 0;
if ( (pid = fork()) > 0 ) {
s_val = 7;
printf("parent: s_val: %d\n", s_val);
} else {
s_val = 9;
printf("child: s_val: %d\n", s_val);
}
return 0;
}
do it,可以猜猜看会发输出什么~
5. 彼可取之current – execve()
进程在执行execve族的函数之后,会把代码段替换成新程序的代码,放弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,惟一保留的就是进程的 ID。也就是说,对系统而言,还是同一个进程,不过执行的已经是另外一个程序了(彼可取而代之!)
这个实验需要,两个文件,hello.c main.c
//hello.c 需要编译成hello.out
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("pid = %d; hello world!\n", getpid());
return 0;
}
//main.c 输出 main.out
#include <stdio.h>
#include <unistd.h>
#define process_name "hello.out"
int create_new_process(const char* name, char* const argv[])
{
int ret = fork();
if ( !ret ) {
execve(name, argv, NULL);
}
return ret;
}
int main()
{
char* const process_avg[] = {"hello.out", NULL};
printf("pid = %d\n", getpid());
printf("child = %d\n", create_new_process(process_name, process_avg) );
printf("end.\n");
return 0;
执行main.out,分析代码执行结果,可以发现,子进程execve之后不会再返回执行副本代码,而是被替换成了hello.out,有点杜鹃鸟的属性~
看文千篇不如动手一练,希望读者可以好好实验,一起探索Linux程序设计!