linux进程基础

  1. 程序的组成 : 指令和数据

指令: 对应cpu的指令集
数据: c语言来说: 
    只读数据:1. const 修饰的变量
2. 字符串
可读可写数据:
初始化的数据

  1. 关于linux生成可执行文件的格式 elf 格式
    a.out 是一个可执行文件的格式, 是工业的二进制标准

    一个elf 程序分为几个段:
    .text : 用来存放指令的段
    .data : 已经初始化全局变量,而不是局部变量

    .bss : 未初始化的全局变量, 这个段的值默认为0
    static 修饰的局部变量,未初始化的
    .rodata : const修饰的变量, 字符串

  2. 进程比程序多一个段, 堆栈段
    “堆栈段” 存放的是函数的返回地址、函数的参数以及程序中的局部变量
    malloc申请的内存也在堆栈段
    堆栈段的大小系统维护, 系统会根据用户使用的情况自动分配大小

  3. 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;
}
  1. 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

  1. 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
---- 领卓教育

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值