- 程序的组成 : 指令和数据
指令: 对应cpu的指令集
数据: c语言来说:
只读数据:1. const 修饰的变量
2. 字符串
可读可写数据:
初始化的数据
-
关于linux生成可执行文件的格式 elf 格式
a.out 是一个可执行文件的格式, 是工业的二进制标准一个elf 程序分为几个段:
.text : 用来存放指令的段
.data : 已经初始化全局变量,而不是局部变量.bss : 未初始化的全局变量, 这个段的值默认为0
static 修饰的局部变量,未初始化的
.rodata : const修饰的变量, 字符串 -
进程比程序多一个段, 堆栈段
“堆栈段” 存放的是函数的返回地址、函数的参数以及程序中的局部变量
malloc申请的内存也在堆栈段
堆栈段的大小系统维护, 系统会根据用户使用的情况自动分配大小 -
fork 创建子进程
pid_t fork(void);
功能:创建子进程
返回值:
创建出一个子进程 ,父子进程都会运行fork函数, fork函数的返回值有2个
父进程fork函数返回子进程的进程号,
子进程fork函数返回0
函数出错返回-1
fork还有一个名字叫做分叉函数,我们可以通过fork函数来创建一个和我们当前进程一样的新进程,并且我们通常把新创建的进程叫做子进程,把之前就存在的进程叫做父进程,并且子进程继承了父进程的整个地址空间,包括了程序上下文,包括堆栈体制,甚至我们上次刚刚说过的PCB他也是直接复制了过来。不过既然这是两个不同的进程那两个进程的进程id是不同的。
我们在Linux可以通过man指令来查看我们的fork函数
fork函数就是来创建一个子进程,如果这个子进程创建成功的话对于父进程来说,就是返回这个子进程的ID,但是对于子进程来说就是返回0。如果返回的是-1,那就代表着进程创建失败了。我们通过程序来看一下fork。
fork函数的应用:
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
int data = 100;
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("fork");
exit(-1);
}
else if(pid == 0) // child process
{
printf("child:pid :%d\n",getpid());// 获取本进程的pid
printf("child:ppid:%d\n",getppid());// 获取本进程的父进程pid
while(1)
{
printf("child:data=%d\n",data);
printf("i am child process\n");
sleep(1);
}
}
else // pid > 0 parent process
{
printf("parent:child pid :%d\n",pid);// 父进程中fork返回值时子进程的进程号
printf("parent:own pid :%d\n",getpid());// 父进程中得到本进程的进程号
printf("parent:parent pid :%d\n",getppid());// 获取本进程的父进程pid
while(1)
{
data ++;
printf("parent:data=%d\n",data);
printf("i am parent process\n");
sleep(1);
}
}
return 0;
}
fork是来创建一个和父进程一样的子进程,但是看我们的输出语句,只是输出了一个输出语句,我们上边也说过了子进程是完全复制了父进程,为什么只有一个进程输出了呢?这里不用想就是我们的父进程输出的,这里我想说的是,我们的子进程在复制父进程的时候是复制的我们的PCB,PCB我们之前也介绍过PCB的其中有一个是我们的程序计数器就是我们下一条指令,这里我们在fork函数的时候printf输出函数已经执行过了, 所以复制的时候复制的是直接是下一个指令地址。所以fork函数之前的指令是不会复制过来的。
下面是信号的父子进程:
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
// SIGINT (ctrl + c ) -> 捕捉
// SIGQUIT (ctrl + \ ) -> 忽略
// SIGFPE -> 捕捉
// SIGUSR1 -> 捕捉
// SIGUSR2 -> 默认
pid_t pid_child1 , pid_child2;
void sighandler(int signum)
{
printf("signum=%d\n",signum);
if(signum == SIGINT)
{
kill(pid_child1,SIGUSR1) ;
kill(pid_child2,SIGUSR2) ;
}
if(signum == SIGUSR1)
{
printf("Child process 1 is killed by parent!\n");
exit(0);
}
if(signum == SIGUSR2)
{
printf("Child process 2 is killed by parent!\n");
exit(0);
}
}
int main(int argc, const char *argv[])
{
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("fork");
exit(-1);
}
else if (pid == 0) // child process1
{
signal(SIGINT,SIG_IGN);
signal(SIGUSR1,sighandler);
while(1)
{
printf("child process1 is running\n");
sleep(1);
}
}
else
{
pid_child1 = pid;
pid = fork();
if(pid < 0)
{
perror("fork");
exit(-1);
}
else if(pid == 0) // child process2
{
signal(SIGINT,SIG_IGN);
signal(SIGUSR2,sighandler);
while(1)
{
printf("child process2 is running\n");
sleep(1);
}
}
else // parent process
{
pid_child2 = pid;
signal(SIGINT,sighandler);
signal(SIGCHLD,sighandler);
waitpid(pid_child1,NULL,0) ;
waitpid(pid_child2,NULL,0) ;
printf("parent process exit !!\n");
exit(0);
}
}
return 0;
}
- ps 命令的使用 , 用来查看系统的进程
ps -ef |grep ./a.out
| : 管道符
grep : 搜索 关键字是 ./a.out 的进程
ps -ef |grep 程序名称
UID PID PPID C STIME TTY TIME CMD
linux 60450 42785 0 14:12 pts/0 00:00:00 ./a.out log
linux 60525 20986 0 14:13 pts/12 00:00:00 ./a.out
linux 60526 60525 0 14:13 pts/12 00:00:00 ./a.out
- exec 函数簇
unistd :unix standard
extern char **environ;
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg,
…, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]);
int execl(const char *path, const char *arg, …);
功能: 在进程中运行另外一个程序
参数:
path : 路径 + 文件名
arg : 运行程序的格式
返回值:
成功不返回:
失败:-1
例如:
execl("/home/linux/work/cource/18071/io/day3/myls",“myls”,"-l","./",NULL);
int execlp(const char *file, const char *arg, …);
功能: 在进程中运行另外一个程序
可以使用系统的path变量
PATH : 是系统的环境变量, 用来保存一些路径, 被保存的路径中的程序 在运行时可以不指定路径名
参数:
path : 文件名(路径可以不写)
arg : 运行程序的格式
返回值:
成功不返回:
失败:-1
$PATH :
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:
例如:
sudo cp /home/linux/work/cource/18071/io/day3/myls /usr/bin
execl(“myls”,“myls”,"-l","./",NULL);
execl(“ls”,“ls”,"-l","./",NULL);
int execv(const char *path, char *const argv[]);
参数:
path : 路径+ 文件名
arg : 运行程序的格式
返回值:
成功不返回:
失败:-1
例如:
char * cmd[] = {“myls”,"-l","./",NULL};
execv("/home/linux/work/cource/18071/io/day3/myls", cmd);
int execvp(const char *file, char *const argv[]);
参数:
path : 文件名(去path指定的路径下去搜索)
arg : 运行程序的格式
返回值:
成功不返回:
失败:-1
---- 领卓教育