精华内容
下载资源
问答
  • 线程和多进程

    2019-03-06 15:09:49
    首先说什么是进程,载入内存中执行的程序,它就是一个进程,而这个程序中执行的某个子任务就是一个线程,程序包含了线程。进程对于线程是唯一的,而一个进程可以有多个线程。程序执行的时候每隔一定时间在多线程之间...

    多线程

    首先说什么是进程,载入内存中执行的程序,它就是一个进程,而这个程序中执行的某个子任务就是一个线程,程序包含了线程。进程对于线程是唯一的,而一个进程可以有多个线程。程序执行的时候每隔一定时间在多线程之间执行,比如第一个线程执行到0.01秒,马上暂停跳到下一个线程开始执行,又执行到0.01秒,返回第一个线程从0.01秒开始执行,往复循环。由于执行和调换的速度特别快,所以感觉像是在同时执行。我们用一段代码就能清晰分辨。

    #include "pch.h"
    #include <iostream>
    #include <thread>
    #include <windows.h>
    
    using namespace std;
    
    
    void output(int i)
    {
    	cout << i << endl;
    }
    
    void pritn()
    {
    	cout << "Hello!" << endl;
    
    }
    
    int main()
    {
    	for (int i=0;i<4;i++)
    	{
    		thread t(output, i);
    		t.detach();
    		thread a(pritn);
    		a.detach();
    	}
    	getchar();
    
    	return 0;
    }
    

    定义一个输出函数,创建两个个线程执行这两个函数。运行结果为
    在这里插入图片描述
    这样就能清晰的明白多线程执行的原理,挨个分段执行。因为加了换行符,所以中间才会空了一行,因为在执行的过程中,两个线程的endl先后执行了。出现这样的输出结果。detach()函数的意思是允许后台执行。

    多进程

    待补充…

    多线程多进程的对比
    在这里插入图片描述
    图片摘自https://blog.csdn.net/lishenglong666/article/details/8557215

    展开全文
  • 多进程初步

    2020-08-05 20:37:30
    进程: 关于进程: 进程初探 ...运行这的程序都是一个进程 系统本身也运行这许多管理系统资源和用户访问的程序 一个程序可以被加载次成为不同的进程 查看:shell ps -ef UID PID PPID C STIME TTY TIME

    进程:
    关于进程: 进程初探
    程序:可执行的二进制代码文件
    进程:程序被加载到内存中运行 系统中基本的执行单元
    联系:具有一定独立功能的程序的一次性活动,操作系统动态执行的单元,包含程序从调度到消亡整个动态过程
    运行这的程序都是一个进程 系统本身也运行这许多管理系统资源和用户访问的程序
    一个程序可以被加载多次成为不同的进程
    查看:shell ps -ef UID PID PPID C STIME TTY TIME CMD
    用户id 进程id 父进程id cpu占用率 开始时间 启动的终端 占用cpu总时间 启动命令
    进程的id就是来区分系统里的那个正在运行的进程 父进程可以创建子进程
    ps -aux 查看进程的详细信息
    状态: s :睡眠 R 运行 执行或即将运行状态
    D :不可中断的睡眠(等待) 通常等待输入或输出的完成
    T:停止 通常是被shell或调试器控制停止
    N:低优先级任务
    Z:僵尸进程 X 死进程 s:进程是会话期首进程
    + :后台进程 (和用户交互的任务)
    l:进程是多线程的
    < :高优先级任务
    kill -9 进程号 //杀死某个进程
    进程描述:
    进程号:进程的标识符(pid) 无符号整型 唯一
    内核限制进程号小于等于32767,达到时重置进程号计数器
    计数器重置从300开始 1-300被系统进程和守护进程占用
    32位的开发平在最大是32767,64位的是2的22次方
    进程状态:
    执行态:该进程正在运行,即进程正在占用cpu,任何时候都只有一个进程
    就绪态:进程已经具备执行的一切条件,正在等待分配cpu的处理时间片
    等待态:进程正在等待某些事件,当前不能分配时间片,进程不能使用cpu,若等待事件发生(等待的资源分配到),则可将其唤醒,变成就绪态
    相关概念:父进程:创建/启动一个进程的进程称之为该进程的父进程
    子进程:相对于该程序的父进程,该进程为子进程
    内存布局:每一个进程都有独立的空间
    每个进程相互独立,都运行在自己的虚拟内存空间里,与其他进程相互隔离(系统为每个进程维护了一个内存映射表,表明物理内存和虚拟内存的对应关系)
    文本段:包含进程运行的程序机器语言指令
    只读性:防止进程通过错误指针以外修改自身的指令
    数据段:初始化数据段:包含显示初始化的全局变量和静态变量 程序加载到内存的时候读取这部分变量
    未初始化数据段(BSS段) 未进行初始化的全局变量和静态变量 程序启动之前,系统将本段的所有的内存初始化为0
    堆:动态开辟的内存
    栈:动态增长和收缩的段,有栈帧组成,存放局部变量,函数参数值等。
    任务调度: 进程间是以调度的方式进行的
    进程特点:动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
    并发性:任何进程都可以同其他进程一起并发执行
    独立性:进程是一个能独立运行的基本单元,同时也是系统分配资源和调度的独立单位
    异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的,不可预知的速度向前推进
    进程创建:
    查看进程号
    getpid 功能:获得进程id
    函数原型:pid_t getpid(void)
    头文件:sys/types.h unistd.h
    参数:无
    返回值:获得该进程的id
    getppid 功能:获得进程id
    函数原型:pid_t fork(void)
    头文件:unistd.h
    参数:无
    返回值:调用该函数的进程的父进程id
    进程创建:fork函数
    功能:创建新进程
    原型:pid_t fork(void)
    头文件:unistd.h
    参数:无
    返回值:在父进程中返回子进程的pid,在子进程中返回0,失败返回-1
    0:子进程 子进程pid(大于0的整数):父进程 -1:出错
    特点:fork成功后,会创建一个子进程,子进程会复制父进程资源,父子进程同时从fork函数
    以下开始并行运行,互不干扰。拥有独立的数据段,堆栈,但无法确定父子进程的运行顺序
    例如:
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <time.h>
    #include <fcntl.h>
    #include <dirent.h>
    #include <strings.h>
    int main(int argc,char *argv[])
    {
    pid_t pid;
    int i=0;
    pid=fork();
    if(pid==0)
    {
    i++;
    printf(“我 子进程\n”);
    printf(“i=%d\n”,i);
    printf(“子进程id:%d\n”,getpid());
    printf(“父进程id: %d\n”,getppid());
    }
    if(pid>0)
    {
    i++;
    printf(“我 父进程\n”);
    printf(“i=%d\n”,i);
    printf(“子进程pid: %d\n”,pid);
    printf(“父进程id:%d\n”,getpid());
    sleep(1);
    }
    return 0;
    }

                vfork函数:
    			功能:创建子进程,并且阻塞父进程
    			原型:pid_t vfork(void)
    			头文件:unistd.h  sys/type.h 
    			参数:无
    			返回值:在父进程中返回子进程pid,在子进程中返回0,失败返回-1
    			特点:vfork成功后,会创建一个子进程,子进程公用(独占)父进程资源,子进程退出 父进程
                      才会得到执行。分享父进程的数据段,堆,一定是子进程先运行。
    			子进程正常退出exit(0);
    

    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <time.h>
    #include <fcntl.h>
    #include <dirent.h>
    #include <strings.h>
    int main(int argc,char *argv[])
    {
    pid_t pid;
    int i=0;
    pid=vfork();
    if(pid0)
    {
    i++;
    printf(“我 子进程\n”);
    printf(“i=%d\n”,i);
    printf(“子进程id:%d\n”,getpid());
    printf(“父进程id: %d\n”,getppid());
    sleep(5);
    }
    if(pid>0)
    {
    i++;
    printf(“我 父进程\n”);
    printf(“i=%d\n”,i);
    printf(“子进程pid: %d\n”,pid);
    printf(“父进程id:%d\n”,getpid());
    // sleep(1);
    }
    return 0;
    }
    特殊进程:
    0号进程 操作系统的引导进程
    祖先进程 操作系统启动的第一个程序,1号进程
    孤儿进程 父进程先退出,子进程被init接管,子进程推出后init会回收其占用的相关资源
    缺点:子进程的相关资源无法清理回收
    僵尸进程 子进程退出,父进程没有做清理工作
    一种非常特殊的进程,它几乎已经放弃了所有内存空间,没有任何可知行代码,也不能
    被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,
    除此之外,僵尸进程不再占有任何内存空间
    父进程退出会清理子进程
    查看僵尸命令ps -elf |grep defunct
    进程等待: wait以及waitpid会等待指定的子进程退出后做清理工作
    wait函数: 功能:等待调用它的进程,直到子进程结束。
    函数原型: pid_t wait(int *status)
    头文件:sys/types.h sys/wait.h
    参数:status若为空,则代表任意状态结束的子进程
    ststus若不为空 则代表指定状态结束的子进程
    一般默认为NULL
    返回值:成功返回终止的那个子进程id,失败返回-1
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <time.h>
    #include <fcntl.h>
    #include <dirent.h>
    #include <strings.h>
    #include <sys/wait.h>
    int main(int argc,char *argv[])
    {
    pid_t pid;
    int i=0;
    pid=vfork();
    if(pid
    0)
    {
    i++;
    printf(“我 子进程\n”);
    printf(“i=%d\n”,i);
    printf(“子进程id:%d\n”,getpid());
    printf(“父进程id: %d\n”,getppid());
    printf(“5s late”);
    sleep(5);
    }
    if(pid>0)
    {
    i++;
    printf(“我 父进程\n”);
    printf(“i=%d\n”,i);
    printf(“子进程pid: %d\n”,pid);
    printf(“父进程id:%d\n”,getpid());
    wait(NULL);
    sleep(50);
    }
    return 0;
    }
    //出现段错误可能是进程没有正常退出的原因
    waitpid函数
    功能:暂时停止目前进程的执行,直到有信号来到或子进程结束
    原型:pid_t waitpid(pid_t pid,int *status,int options)
    头文件:sys/types.h sys/wait.h
    参数: pid >0 等待指定的pid
    -1 等待任意的pid
    status:保存进程退出时状态 一般为null
    options WNOHANG :若由pid指定的子进程不立即可用,则waitpid不阻塞,此时返回值为0
    0 同wait ,阻塞父进程,等待子进程退出
    返回值:成功返回子进程识别码(PID),如果有错误发生则返回-1
    waitpid(pid,NULL,0) //指定的进程退出
    waitpid(-1,NULL,0) 同wait(NULL);
    进程退出方法:
    exit() 标准函数(stdlib.h) //正常结束一个进程会清理缓冲区 0表示正常结束,其它值表示错误,进程非正常结束
    _exit() 系统调用函数(unistd.h)//结束一个进程不会清理缓冲区,exit和_exit函数都是用来终止进程的。当程序执行到
    exit和_exit时,进程会无条件的停止剩下的所有操作,清除包数据结构,终止本进程的运行
    return //自然返回也会结束进程 return语句会被编译器翻译为调用exit
    信号: ctrl+c //ctrl+\ //kill -9 进程号 (杀死指定进程)
    常用的函数族: exec函数族可以在一个进程中启动另一个进程,会覆盖原有进程,一般与vfork连用
    int execl(const char *path, const char *arg, …);逐个列举的方式
    int execlp(const char *file, const char *arg, …);从PATH 环境变量中查找文件并执行
    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[]);
    execl 功能:使用完整的文件目录来查找对应的可知行文件。注意目录必须以“/”开头,否则将其视为文件名
    原型:int execl(const char
    path,const char *arg,)
    头文件:unistd.h
    参数: path 执行文件的路径
    arg: 可知行文件所需要的参数
    参数要以null结尾
    返回值:无
    特点:当调用execl函数的时候,程序的代码段发生变化,变为execl要执行的功能的代码段
    必须以null表示结束,如果使用逐个列举方式,那末要把它强制转换成一个字符指针
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <time.h>
    #include <fcntl.h>
    #include <dirent.h>
    #include <strings.h>
    #include <sys/wait.h>
    int main(int argc,char *argv[])
    {
    pid_t pid;
    pid=vfork();
    if(pid==0)
    {
    execl("./a.out",“a.out”,NULL);
    }
    return 0;
    }
    execlp execlp()会从PATH环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件
    然后将第二个以后的参数当作该文件的argv[0],argv[1],z最后一个参数必须用空指针NULL作结束。如果用常数0来表示一个空指针,则必须将他
    强制转换为一个字符指针否则将它解释为整形参数
    原型: int execlp (const char *file,const char *arg,…(char *)0);
    shell命令调用:
    system #include <stdlib.h>
    int system(const char *command )

    展开全文
  • Linux7:进程初步:进程相关概念,创建进程,特殊...运行着的程序都是一个进程 系统本身也运行着许多管理系统资源和用户访问的程序 一个程序可以被加载次成为不同的进程 查看进程: windows操作系统下: 任务管理器

    Linux7:多进程初步:进程相关概念,创建进程,特殊的进程,进程资源清理,进程退出,exec函数族以及system函数

    1.进程描述:

    进程初探:

    程序
    可执行的二进制代码文件
    进程
    程序被加载到内存中运行
    系统中基本的执行单元
    联系
    具有一定独立功能的程序的一次运行活动,操作系统动态执行的单元,包含程序从调度到消亡的整个过程是动态的过程
    运行着的程序都是一个进程
    系统本身也运行着许多管理系统资源和用户访问的程序
    一个程序可以被加载多次成为不同的进程

    查看进程:

    windows操作系统下:
    任务管理器:
    在这里插入图片描述

    Linux 操作系统下:
    shell命令:

    ps命令:
    
    ps -ef
      UID      PID        PPID             C       STIME       TTY           TIME             CMD
    用户ID    进程ID号    父进程ID      CPU占用率    开始时间    启动的终端   占用CPU总时间      启动命令
    
    
     ps -aux//查看进程的详细信息
      stat
       S:睡眠
       R:运行
        执行或即将运行状态
       D:不可中断的睡眠(等待)
        通常等待输入或输出的完成
       T:停止
        通常是被shell或调试器控制停止
       N:低优先级任务
        nice值被修改
       Z
        僵尸进程
       X
        死进程
       s:进程是会话期首进程
       +:后台进程
        和用户交互的任务
       l:进程是多线程的
       <:高优先级任务

    在这里插入图片描述
    在这里插入图片描述
    进程号:

    进程的标识号(pid) 无符号整形 唯一
    内核限制进程号小于等于32767,达到时重置进程号计数器
    计数器重置从300开始,1-300被系统进程和守护进程占用
    32位开发平台最大是32767,64位达2的22次方
    /proc/sys/kernel/pid_max

    进程状态:

    执行态:该进程正在运行,即进程正在占用 CPU, 任何时候都只有一个进程。
    就绪态:进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间片。
    等待态:进程正在等待某些事件,当前不能分配时间片, 进程不能使用 CPU,若等待事件发生(等待的资源分配到)则可将其唤醒,变成就绪态

    相关概念:

    父进程
    创建/启动一个进程的进程称之为该进程的父进程
    子进程
    相对于改程序的父进程,该进程为子进程
    父子进程是相对的概念

    内存布局:

    每一个进程有独立的空间
    文本段
    包含进程运行的程序机器语言指令
    只读性
    防止进程通过错误指针修改自身的指令
    数据段
    初始化数据段
    包含显示初始化的全局变量和静态变量
    程序加载到内存的时候读取这部分变量
    未初始化数据段(BSS段)
    未进行初始化的全局变量和静态变量
    程序启动之前,系统将本段所有的内存初始化为0

    动态开辟的内存

    动态增长和收缩的段,由栈帧组成,存放局部变量、函数参数值等

    如图:
    在这里插入图片描述

     size命令 
      //查看进程所占资源
    

    任务调度:

    按一定的算法,从一组待运行的进程中选出一个进程占用CPU

    进程特点:

    动态性
    并发性
    独立性
    异步性

    杀死进程:

    ps  //查看进程
    kill -9 进程ID   //杀死进程

    2.进程的使用:

    子进程:

    用户进程创建子进程,子进程存在于系统,独立于父进程
    可被系统调度,可被分配系统资源

    查看进程号:

    getpid:
    功能
    获得进程id
    函数原型
    pid _t getpid(void)
    所属头文件
    #include <sys/types.h>
    #include <unistd.h>
    参数

    返回值
    调用该函数的进程id

    getppid:
    功能
    获得父进程id
    函数原型
    pid_t getppid(void)
    所属头文件
    #include <sys/types.h>
    #include <unistd.h>
    参数

    返回值
    调用该函数的进程的父进程id

    创建进程:

    fork函数:
    功能:
    创建新进程
    原型
    pid_t fork(void)
    所属头文件
    <unistd.h>
    参数

    返回值
    在父进程中返回子进程的PID,在子进程中返回0,失败返回-1
    特点
    fork成功后,会创建一个子进程,子进程会复制父进程资源父子进程同时从fork函数以下开始并行运行。互不干扰。拥有独立的数据段、堆栈,但无法确定父子进程的运行顺序

    代码演示demo2.c:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    int main()
    {
    pid_t pid;
    pid=getpid();
    fork();//创建一个进程,两个进程在运行,返回两个pid
    if(pid==getpid())
    {
     printf("fujincheng\n");
    }else
    {
     printf("zijincheng\n");
    }
    printf("my pid :%d\n当前pid:%d\n",pid,getpid());
    return 0;
    }
    

    运行结果:
    在这里插入图片描述

    vfork函数:
    功能
    创建子进程,并且阻塞父进程
    原型
    pid_t vfork(void)
    所属头文件
    <unistd.h> <sys/type.h>
    参数

    返回值
    在父进程中返回子进程的PID,在子进程中返回0,失败返回-1
    特点
    vfork成功后,会创建一个子进程,子进程共用(独占)父进程资源,子进程退出父进程才会得到执行。分享父进程的数据段、堆,一定是子进程先运行
    注意
    使用vfork的时候,为了保证子进程比父进程先运行,只有子进程运
    行exec或者exit函数之后,才会去运行父进程
    ,否则会发生段错误

    代码演示:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <stdlib.h>
    int main()
    {
      int cnt=0;
      pid_t pid;
      pid=vfork();//创建子进程
      if(pid>0)
      {
       while(1){
       printf("fujincheng\n");
       sleep(1);
       }
      }else if(pid==0)
      {
       while(1){
       printf("ZIjincheng\n");
       sleep(1);
       cnt++;
       if(cnt==3)
       {
         exit(0);
       }
       }
      }
     return 0;
    }
    

    代码实现:当子进程中cnt==3时,退出,再去执行父进程

    运行结果:
    在这里插入图片描述

    特殊进程:

    0号进程:
    操作系统的引导程序
    祖先进程:
    操作系统启动的第一个程序,1号进程
    孤儿进程:
    父进程先退出,子进程被init接管,子进程退出后init会回收其占用的相关资源
    在Ubuntu的图形界面下,孤儿进程会被upstart收养而不是init
    upstart是Ubuntu使用的用来代替init的,可更快的启动系统,以及在硬件热拔插的时候启动或者停止相关服务
    ps -x |grep +僵尸进程的进程号
    缺点
    子进程的相关资源无法清理回收
    僵尸进程:
    子进程退出,父进程没有做清理工作
    一种非常特殊的进程,它几乎已经放弃了所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间
    父进程退出会清理子进程

    进程等待:

    wait以及waitpid会等待指定的子进程退出然后做清理工作
    wait函数
    功能
    等待调用它的进程,直到子进程结束
    函数原型
    pid_t wait(int *status);
    所属头文件
    <sys/types.h><sys/wait.h>
    参数
    status 若为空,则代表任意状态结束的子进程
    status 若不为空,则代表指定状态结束的子进程
    一般默认为NULL
    返回值
    成功返回终止的那个子进程的id,失败返回-1

    wait代码演示:

    #include <sys/types.h>
    #include <sys/wait.h> 
    #include <unistd.h> 
    #include <stdlib.h>
     #include <stdlib.h> 
    #include <stdio.h> 
    int main() 
    { 
    pid_t pid,pc; 
    int status; 
    printf("wait实例:\n"); 
    pid=fork(); 
    if(pid<0)//创建出错, 
    printf("error ocurred!\n"); 
    else if(pid == 0) //如果是子进程 
    { 
    printf("我是子进程的ID=%d\n",getpid());
     sleep(10); //睡眠10秒 
    exit(7); 
    } 
    else //父进程 
    { 
    pc=wait(&status); //等待子进程结束; 得到子进程的ID
    if(WIFEXITED(status)) //子程序正常结束返回非0值,异常返回0
    { 
    printf("我是父进程,我等待的子进程的id号=%d\n",pc); 
    printf("退出码是%d\n",WEXITSTATUS(status)); 
    } 
    else 
    { 
    printf("子进程退出异常!\n"); 
    } 
    } 
    exit(0);
    }
    

    代码实现:父进程等待子进程退出。
    在第3行结果打印出来前有10 秒钟的等待时间,这就是我们设定的让子进程睡眠的时间,只有子进程从睡眠中苏醒过来,它才能正常退出,也就才能被父进程捕捉到
    运行结果:
    在这里插入图片描述

    waitpid函数
    功能
    暂时停止目前进程的执行,直到有信号来到或子进程结束
    原型
    pid_t waitpid(pid_t pid,int * status,int options);
    所属头文件
    #include<sys/types.h>
    #include<sys/wait.h>
    参数
    status:保存进程退出时状态
    pid
    0:等待指定的pid
    -1:等待任意的PID
    options
    0:同 wait,阻塞父进程,等待子进程退出–一般为0
    返回值
    成功返回子进程识别码(PID) ,如果有错误发生则返回返回值-1
    waitpid(pid,NULL,0);//指定的进程退出
    waitpid(-1,NULL,0)//同wait(NULL);

    waitpid代码演示:

    #include <sys/types.h>
    #include <sys/wait.h> 
    #include <unistd.h> 
    #include <stdlib.h>
     #include <stdlib.h> 
    #include <stdio.h> 
    int main() 
    { 
    pid_t pid,pc;
     pid=fork(); 
    int status; 
    if(pid<0) 
    { 
    printf("创建进程失败!\n"); 
    } 
    else if(pid==0) 
    { 
    printf("我是子进程,我的ID=%d\n",getpid());
     sleep(10); 
    exit(0); 
    } 
    else 
    { 
    do
    { 
    pc=waitpid(pid,&status,WNOHANG);//使用了WNOHANG参数,waitpid就不会等待,直接返回0. 
    // pc=waitpid(pid,&status,0); 
    if(pc==0) 
    { 
    printf("没有收集到子进程!\n"); 
    sleep(1); 
    } 
    }while(pc==0);//等不到,继续等, 
    if(pid==pc) 
    printf("等到了子进程\n");
     else printf("出错了\n");
     printf("我是父进程,我要等的进程id是%d\n",pc); 
    } 
    exit(0); 
    }
    

    运行结果:

    在这里插入图片描述
    从结果看出:

    先执行父进程,输出"没有收集到子进程",然后sleep(1),此时执行了子进程,输出"我是…31842",sleep(10);然后执行父进程,因为父进程不会等待子进程,所以不断的收集子进程,直到子进程sleep(10),结束后,才会收集到.

    进程退出:

    方法:
    exit();//正常结束一个进程会清理缓冲区
    0 表示正常结束;其他值表示错误,进程非正常结束
    函数的参数可在shell中查看
    _exit();直接进入内核释放用户进程的地址空间
    exit 和_exit 函数都是用来终止进程的。当程序执行到 exit 或_exit 时,进程会无条件地停止剩下的所有操作,清除包数据结构,并终止本进程的运行。
    return //自然返回也会结束进程
    return语句会被编译器翻译为调用exit
    信号
    ctrl + c
    ctrl +
    kill -9 进程号
    //杀死指定进程

    退出清理函数:

    函数原型
    int atexit(void (*function)(void));
    函数功能
    注册退出清理函数,在任意进程结束的时候,自动执
    行退出清理函数
    函数参数
    void (*function)(void)
    函数指针,指向一个无参数,无返回值的函数
    函数返回值
    成功返回0,失败返回非0值
    注意:该函数不需要被调用,只要在函数
    开始之前进行注册,在进程结束的时候就会自己执行

    参考代码:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    int i=0;
    void clean(void)
    {
    i++;
    printf("i=%d\n",i);
    }
    int main()
    {
    atexit(clean);
    fork();
    fork();
    }

    运行结果:
    在这里插入图片描述
    atexit:
    是在进程结束的时候自动执行清理函数。

    3.执行程序:

    常用的函数族:

    exec 函数族就提供了一个在进程中启动另一个程序执行

    #include <unistd.h>
    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[]);

    使用原因:
    当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何 exec 函数族让自己重生
    如果一个进程想执行另一个程序,那么它就可以调用 fork 函数新建一个进程,然后调用任何一个 exec,这样看起来就好像通过执行应用程序而产生了一个新进程。

    exec函数族:
    int execl(const char *path, const char *arg, …);逐个列举的方式
    int execlp(const char *file, const char *arg, …);从PATH 环境变量中查找文件并执行
    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[]);
    l->list
    命令参数以列表的方式提供,NULL结尾
    v->vector
    命令参数以二维数组形式提供,数组的每一行为一个命令行参数
    e->environment
    传递给程序的环境列表

    execl
    功能
    使用完整的文件目录来查找对应的可执行文件。注意目录必须以“/”开头,否则将其视为文件名
    原型
    int execl(const char *path, const char *arg, …);
    所属头文件
    #include <unistd.h>
    参数
    path:执行文件的路径
    arg:可执行文件所需要的参数
    参数要以NULL 结尾 (char *)0
    返回值

    特点
    当调用execl函数的时候,程序的代码段发生变化,变为execl要执行的功能的代码段,必须以 NULL 表示结束,如果使用逐个列举方式,那么要把它强制转化成一个字符指针
    system:
    运行shell指令系统函数正常函数调用

    参考代码:execl和system函数的比较:

    演示代码:

    /*******************************
    *文件名称: stack.c
    *创建时间:20.10.10
    *修改时间:20.10.10
    *文件功能:顺序栈
    *文件版本:v1.0
    ********************************/
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #define MAX 7
    enum result
    {
     ERR=-1,OK
    };
    struct stack
    {
     int data[MAX];
     int top;
    };
    int push(struct stack *p,int num);
    int pop(struct stack *p,int *d);
    int main()
    {
     struct stack s;
     s.top = -1;
     int i = 0,num;
     for(i=0;i<9;i++)
     {
      if(push(&s,i)==-1)
       printf("%d\t栈满,无法继续添加数据\n",i);
     } 
     printf("~~~~~~~~~~~~~\n");
     //execl("/bin/ls","ls","-l",NULL);//覆盖原程序,进行执行
     system("ls -l");//执行终端指令  ---执行完,继续原程序
     for(i=0;i<9;i++)
     {
      if(pop(&s,&num) ==0)
       printf("%d 出栈\n",num);
      else
       printf("栈空\n");
     }
     return 0;
    }

    execl和fork函数的搭配使用:

    演示代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    int main()
    {
     int num = 10;
     pid_t pid = fork();
     if(pid < 0)
     {
      perror("fork");
      return -1;
     }
     else if(pid == 0)
     {
      printf("child process\n");
      execl("/bin/ls","ls","-l",NULL);
     }
     else
     {
      wait(NULL);
      printf("parent process\n");  
     }
     return 0;
    }
    

    运行结果:
    在这里插入图片描述
    在这里插入图片描述

    execl和vfork函数的搭配使用:

    vfork父子进程资源共享:在调用exit,exec函数族之前和父进程共享资源。
    补充:子进程结束必须要exit或者函数族,如果不使用,运行时会出现段错误。

    演示代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    int main()
    {
     int num = 10;
     pid_t pid = vfork();
     if(pid < 0)
     {
      perror("vfork");
      return -1;
     }
     else if(pid == 0)
     {
      num++;
      printf("child process\n");
      execl("./w","./w","/home/li/text","./89",NULL);
      exit(0);
     }
     else
     {
      printf("parent: num=%d\n",num);
      printf("parent process\n");
     }
     return 0;
    }
    

    运行结果:和fork一样
    在这里插入图片描述
    在这里插入图片描述

    execlp:
    execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数
    原型
    int execlp(const char * file,const char * arg,…,(char *)0);

    演示代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    int main()
    { 
      //execl("/bin/ls","ls","-l",NULL);
      execlp("ls","ls","-l",NULL);
     return 0;
    }
    

    运行结果:

    在这里插入图片描述

    execle:
    可以传递一个指向环境字符串指针数组的指针。
    例如:
    char *env_init[] = {“AA=aa”,”BB=bb”,NULL};

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    int main()
    { 
      char *envp[]={"AA=HELLO","BB=123",NULL};//sizeof(envp)=12;shuzuzhizhen(4)
      //execl("/bin/ls","ls","-l",NULL);
      //execlP("ls","ls","-l",NULL);
      execle("/bin/ls","ls","-l",NULL,envp);  
     return 0;
    }
    

    运行结果:
    在这里插入图片描述

    execv:
    应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
    例如:
    如char *arg[]这种形式,且arg最后一个元素必须是NULL
    char *arg[] = {“ls”,”-l”,NULL};

    演示代码:
    execv.c

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    extern char **environ;
    int main()
    { 
     char *arg[]={"./hello",NULL}; 
     execv("./hello",arg); 
     return 0;
    }

    hello.c

    #include <stdio.h>
    #include <unistd.h>
    extern char **environ;
    int main()//循环打印环境变量
    {
     printf("%s is called %d\n",__FILE__,__LINE__);
     
     while(*environ)
     {
      printf("%s\n",*environ++);
     } 
      return 0;
    }

    运行结果:
    在这里插入图片描述

    5.shell命令调用:

    system
    函数原型
    #include <stdlib.h>
    int system(const char *command);
    函数功能
    执行可执行程序
    函数参数
    command–要执行的可执行程序
    函数返回值
    参考man帮助

    system函数通过调用shell程序/bin/sh–c来执行string所指定的命令,该函数在内部是通过调用fork、
    execve(“/bin/sh”,…)、waitpid函数来实现的。通过system创建子进程后,原进程和子进程各自运行,相互间
    关联较少。如果system调用成功,将返回0。

    参考文章:
    多进程初步
    参考结构流程图:
    多进程初步
    注:需要使用xmind软件进行查看

    展开全文
  • 进程

    2020-08-09 11:50:31
    进程的定义 进程: 一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。 进程的组成 ...通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。 进程与程序的区别 进程

    进程的定义

    进程: 一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。

    进程的组成

    一个进程应该包括:

    1. 程序的代码;
    2. 程序处理的数据;
    3. 程序计数器中的值,指示下一条将运行的指令;
    4. 一组通用的寄存器的当前值,堆、栈;
    5. 一组系统资源(如打开的文件)

    总之,进程包含了正在运行的一个程序的所有状态信息。

    进程与程序的联系

    1. 程序是产生进程的基础
    2. 程序的每次运行构成不同的进程
    3. 进程是程序功能的体现
    4. 通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。

    进程与程序的区别

    1. 进程是动态的,程序是静态的:程序是有序代码的集合;进程是程序的执行,进程有核心态/用户态
    2. 进程是暂时的, 程序的永久的:进程是一个状态变化的过程,程序可长久保存
    3. 进程与程序的组成不同:进程的组成包括程序、数据和进程控制块(即进程状态信息)

    在这里插入图片描述

    进程的特点

    ●动态性:可动态地创建、结束进程;
    ●并发性:进程可以被独立调度并占用处理机运行;并发并行
    ●独立性:不同进程的工作不相互影响;
    ●制约性:因访问共享数据/资源或进程间同步而产生制约。

    进程的生命期管理:

    进程创建
    引起进程创建的3个主要事件:

    1. 系统初始化时;
    2. 用户请求创建一个新进程;
    3. 正在运行的进程执行了创建进程的系统调用;

    进程运行
    内核选择一个就绪的进程, 让它占用处理机并执行(调度算法)

    进程等待
    在以下情况下,进程等待(阻塞) :
    1请求并等待系统服务,无法马上完成.
    2启动某种操作,无法马上完成
    3需要的数据没有到达

    进程只能自己阻塞自己,因为
    只有进程自身才能知道何时需
    要等待某种事件的发生。

    进程唤醒
    唤醒进程的原因:

    1. 被阻塞进程需要的资源可被满足
    2. 被阻塞进程等待的事件到达
    3. 将该进程的PCB插入到就绪队列
      进程只能被别的进程或操作系统唤醒。

    进程结束
    在以下四种情形下,进程结束:

    正常退出( 自愿的)

    错误退出(自愿的)

    致命错误(强制性的)

    被其他进程所杀(强制性的)

    进程状态变化模型

    进程的三种基本状态:
    进程在生命结束前处于且仅处于三种基本状态之一 不同系统设置的进程状态数目不同。
    运行状态(Running):当一个进程正在处理机.上运行时。
    就绪状态(Ready):一个进程获得了除处理机之外的一切所需资源,一旦得到处理机即可运行.
    等待状态(又称阻塞状态Blocked): 一个进程正在等待某-事件而暂
    停运行时。如等待某资源,等待输入/输出完成。
    在这里插入图片描述

    进程挂起

    Why ?合理且充分地利用系统资源。
    进程在挂起状态时,意味着 进程没有占用内存空间。处在挂起状态的
    进程映像在磁盘.上。
    在这里插入图片描述
    挂起状态
    阻塞挂起状态(Blocked- suspend) :进程在外存并等待某事件的出现;
    就绪挂起状态(Ready- suspend) :进程在外存,但只要进入内存,即可运行

    挂起(Suspend) :把一个进程从内存转到外存 可能有以下几种情况:

    阻塞到阻塞挂起:没有进程处于就绪状态或就绪进程要求更多内存资源时,会进行这种转换,以提交新进程或运行就绪进程;

    就绪到就绪挂起:当有高优先级阻塞(系统认为会很快就绪的)进程和低优先就绪进程时,系统会选择挂起低优先级就绪进程;

    运行到就绪挂起:对抢先式分时系统,当有高优先级阻塞挂起进程因事件出现而进入就绪挂起时,系统可能会把运行进程转到就绪挂起状态;

    ●阻塞挂起到就绪挂起:当有阻塞挂起进程因相关事件出现时,系统会把阻塞挂起进程转换为就绪挂起进程。

    状态队列

    由操作系统来维护一组队列,用来表示系统当中所有进程的当前状态

    不同的状态分别用不同的队列来表示(就绪队列、各种类型的阻塞队列)

    每个进程的PCB都根据它的状态加入到相应的队列当中,当一个进程的状态发生变化时,它的PCB从一个状态队列中脱离出来,加入到另外一个队列。.

    展开全文
  • 进程是被执行的应用程序,同时也是系统资源分配的最小单位(虚拟地址空间等资源,见下图),一个进程中可以包含多个线程。操作系统会为每个进程分配一定的虚拟地址空间,该虚拟地址空间由进程独享 线程则是CPU进行...
  • 一、进程/线程 ...总结:一个进程包含多个线程,多个线程共同完成任务;进程间也可以通信,但代价较高。 二、浏览器多进程 主要包括几个进程 Browser进程: 浏览器主进程,有且仅有一个 ...
  • Java进程线程(

    2020-06-26 22:53:28
    简而言之:一个程序运行后至少有一个进程一个进程中可以包含多个线程 举例说明 360软件进入内存运行 效率取决于cpu, 早期的cpu只有一核,cpu会在多个线程之间进行高速的切换,现在cpu是多核,每一..
  • 一个进程中可以有多个线程,这些线程共享进程的所有资源,线程本身只包含一点必不可少的资源。 CPU相当于转盘 分配给每个线程一定相同的时间 时间到了之后就会转到下个线程 单线程:如果事件1 阻塞之后 CPU转一圈...
  • 我知道一个应用程序由一个进程多个进程组成,一个进程可以包含多个线程,但至少包含一个线程。进程之间的空间是独立的,一个进程内多个线程共享内存空间的。仅仅只是这些吗?我对自己也要说呵呵了,还是多找些资料...
  • Linux的进程相互之间有一定的关系。比如说,在Linux进程基础中,...进程组 (process group)每个进程都会属于一个进程组(process group),每个进程组中可以包含多个进程。进程组会有一个进程组领导进程(process gro...
  • Python多进程和线程

    2020-12-21 13:02:15
    进程一个具有一定功能的程序在一个数据集上的一次动态执行过程。进程由程序,数据集合和进程控制块三部分组成。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集合是程序在执行时需要的数据和工作区...
  • 7.1 进程的定义 一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程 7.2 进程的组成 ...通过多次执行,一个程序对应多个进程,通过调用关系,一个进程包括多个程序 7.3 进程的特点 动态性,...
  • 一个进程至少包含一个主线程,也可以有更的子线程。 线程拥有自己的栈空间。 进程和线程都是操作系统管理的 线程有 初始化 可运行 运行中 阻塞 销毁 五种状态 这五种状态是通过JVM 操作 操作系统内核中的TCB...
  • 进程概念

    2019-09-05 00:43:27
    进程概念 进程的定义 进程是指一个具有一定独立功能的程序关于某个数据集合的一次运行活动...进程一定包含一个程序,因为程序是进程完成相应功能的逻辑描述;而一个程序可以对应多个进程。 进程的状态和变迁 进程...
  • 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程,当一个 程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程.一定的独立功能,进程是系统进行...
  • 进程 PCB 进程挂起

    2019-03-08 13:59:00
    进程一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。 只有当一个程序被OS加载到内存中,cpu对其执行时,这个过程是动态的,称为进程。 7-2 进程的组成 包含了正在运行的一个程序的所有状态...
  • 众所周知,Python 中的多线程是一个假的多线程,对于多核 CPU,由于受限于 GIL 全局解释锁,同一时刻只能...1、单线程在单线程程序中可能包含多个方法,运行程序后,默认是在一个主线程里按顺序运行。import timedef...
  • 关联:进程一定包含一个程序,一个程序可以对应多个进程 4.2.2 进程的状态及变迁 多任务系统中进程的基本状态: ①就绪状态(ready):进程已获得除CPU之外的运行所必需的资源,一旦得到CPU的控制权,立即就可
  •  一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程是一种抽象的概念,从来没有统一的标准定义。进程一般由程序,数据集合...
  • 进程:一个进程包括有操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在。它必须是进程的一部分。一个进程一直运行直到所有的非守护线程都结束运行后才能结束。进程线程定义进程是指处于运行中的...
  • 1.进程 进程是具有一定独立功能的程序在某个数据集合上的一次运行,是系统进行...一个进程包含多个线程。 1> 用户级线程 在用户程序中实现的线程,不依赖于操作系统核心。但同一进程中同时只能有一个线...
  • 进程和线程

    2019-07-03 10:31:27
    1.1 多线程介绍 进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于...简而言之:一个程序运行后至少有一个进程一个进程中可以包含多个线程 单线程程序:即,若有多个任...
  • 进程线程

    2019-09-22 19:45:03
    几乎所有的操作系统都只支持同时运行多个任务,一个任务就是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程。 1.1 进程与线程 进程是...
  • 什么是进程,线程,两者联系与区别? 进程:一个正在运行的程序,进程为系统中分配内存资源的最小单元; 线程:线程是程序执行的最小单位,线程...(2) 线程只是一个进程的不同执行路径,线程有自己的堆栈和局部变量,
  • Linux的进程相互之间有一定的...进程组 (process group)每个进程都会属于一个进程组(process group),每个进程组中可以包含多个进程。进程组会有一个进程组领导进程(process group leader),领导进程的PID成为进程...
  • shell多进程执行

    2020-07-26 12:45:05
    shell脚本是将要执行的命令按一定顺序写成的一个文本文件,最近遇到一个需求,要将一定数量的命令快速执行,而每次执行都需要一定的时间,最终使用 &提交后台执行来完成,如: cat test.txt | grep abc > abc...
  • Linux的进程相互之间有一定的关系。比如说,在Linux进程基础...进程组 (process group)每个进程都会属于一个进程组(process group),每个进程组中可以包含多个进程。进程组会有一个进程组领导进程 (process group le...
  • 进程一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进程要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 795
精华内容 318
关键字:

一个进程一定包含多个进程