多进程_多进程编程 - CSDN
精华内容
参与话题
  • 进程及多进程编程

    千次阅读 2018-08-17 15:05:56
    第一部分 进程知识总结  一、进程的定义 进程是执行中的程序,就类比于一出舞台剧的整个表演过程;进程动态性的实质是进程实体的执行过程...进程的并发性是内存中可以允许存在进程实体,并且可以同时运行一...

                                                                                  第一部分  进程知识总结 

    一、进程的定义

    进程是执行中的程序,就类比于一出舞台剧的整个表演过程;进程动态性的实质是进程实体的执行过程;进程独立性是指每个进程都有自己的PCB;进程的并发性是内存中可以允许存在多个进程实体,并且可以同时运行一段时间;

    二、进程的PCB分配

        内核为我们维护了一个task_list的双向循环链表,每个链表节点都是一个task_struct(进程描述符)类型,在inux系统下主要依靠slab分配器分配task_struct结构,这些task_struct结构存在于内核栈的尾部,通过栈指针可以搜索到他们的位置,在内核栈的尾部分配出一个thread_info结构体,这个结构体中存放了实际指向task_struct结构的指针;

       每个PCB中存放了唯一标识进程的pid_t类型的pid号,实际上就是一个int类型;pid的默认最大值类型为一个short int 的最大值---32768;另外还存放了其他信息:

    • 用于进程标识信息的进程标识符 

        内部标识符:由操作系统提供的唯一的进程序号;

        外部标识符:用户创建的由数字和字母组成的字符串,便于创建者使用该进程;

       通常如果有父子关系,还会设置ppid和pid来标识父子关系

    • 用于进程处理机状态信息

        通用寄存器:供用户程序访问暂存信息

        指令寄存器:存放下一条指令的地址

        程序状态字:含有状态信息条件码、执行方式、中断屏蔽标志

        用户栈指针:存放过程和系统调用参数及调用地址,可以保存现场信息,下一次调度时可以继续执行

    • 用于进程调度信息

          进程的优先级 进程的状态

    三、进程的状态

      进程的主要状态有:就绪、阻塞、运行,三者之间的关系如图所示:

    进程被替换的两种情况:

    • 第一种为主动情况,该进程执行完自己的任务主动将CPU让出或者该进程执行有阻塞操作,操作系统将会挂起该进程执行新进程
    • 第二种为被动情况,当一个进程被操作系统认为长时间占用CPU时会主动用另一进程替换正在运行的此进程;保证每个进程公平的占用CPU
    • 上图中,进程不会由阻塞转为执行态:CPU每次进程调度是在就绪队列中选择进程运行,不会在阻塞队列中调度进程;(理解难点:当阻塞状态等待事件发生时进程是转为就绪态而不是直接转为执行态
    • 上图中,进程不会由就绪-->阻塞态,由于就绪态的进程并没有执行就不会出现阻塞状态。

    ,四、进程的创建

        linux下使用pid_t fork()系统调用函数创建进程,该函数一次执行,返回两次,在父进程中返回子进程的pid,在子进程中返回0;子进程和父进程的代码段完全相同,并且父子进程共享fork之前打开的文件描述符,当有子进程产生时,文件描述符的引用计数加1;

    通常我们创建新进程是为了执行新的不同的程序,所以出现了进程替换,使用一组进程替换函数使得新进程执行新的程序;

    五、处理僵尸进程

    (1)僵尸进程

        定义1:父进程未结束,子进程结束,并且父进程未获取子进程的退出数据;

        定义2:一个进程的进程主体释放,而其PCB未释放;

    (2)解决僵尸进程

       本质是只要让父进程能得到子进程结束的信息后在结束

     第一种方法:pid_t wait(int *stat):

       阻塞运行:函数被调用后不会立即返回,等待某些条件的发生才会返回;

       wait函数会阻塞运行;等待子进程结束才能返回,致使父进程阻塞到wait调用处;

      wait函数的缺点:一个wait函数只能处理一个僵尸进程,在实际中无法预测到底有多少个僵尸进程,这就阻碍了我们能处理僵尸进程的能力,引入了异步处理方式:信号

    第二种方法:信号

    绑定信号及其响应方式,只要有子进程结束的信号就通知父进程。

    具体做法:

        当子进程结束时会发出SIGCHLD信号,但是一般处于默认操作,所以我们可以利用信号处理函数通过修改信号响应方式来向父进程传递子进程结束的状态数据;

      修改的响应方式:当子进程结束时SIGCHLD信号通过绑定的fun函数调用wait函数来处,当不存在子进程结束时父进程照常运行;当存在子进程先于父进程结束时通过SIGCHLD信号通过fun函数告诉父进程有僵尸进程需要处理,比不需要之前父进程要一直等待子进程结束后才能运行,代码如下:

     

    僵尸进程的坏处:从定义可得知,僵尸进程会占用PCB实体,但是并没有实际应用,造成PCB资源的浪费,如果存在过多的僵尸进程,会造成新进程因不能分配到PCB而无法执行。

    六、处理孤儿进程

    (1)孤儿进程

          指得是当父进程结束时子进程还未结束,这时候孤儿进程的父进程就变为守护进程init;

    (2)模拟孤儿进程 可以看到被init守护进程回收管理

      七、守护进程

    (1)守护进程

    在后台运行,不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务;

    守护进程是完全脱离终端在后台运行的,脱离终端的目的是不让在终端被显示;

    (2)创建守护进程

       守护进程编程流程

       1.首先调用umask()函数将文件模式创建屏蔽字置为0;

       2.调用fork()然后父进程退出,这样做的目的:一是如果该守护进程作为一条简单的shell命令启动,那么父进程终止是使shell认为这条命令已经执行完成;二是子进程继承父进程的进程组ID,但是具有一个新进程的ID,这就保证了子进程不是一个组长进程。这是调用setid()的必要条件

       3.调用setid()创建新的会话,这样使调用进程成为新会话的首进程,成为新进程的组长进程,没有控制终端

       4.调用fork(),然后父进程退出,这样保证了进程不再是会话组长,从而不能打开一个新的终端

       5.将当前工作目录改为根目录,调用chdir()实现

       6.关闭不需要的文件描述符,可以通过getrlimit函数获得最大描述符值,关闭从该值到最大描述符值的所有文件描述符

      7.打开“/dev/null”并且使其具有文件描述符0,1,2,这样任何一个试图通过标准输入、写标准输出或标准错误输出得到的库函数没有任何效果,因为守护进程不与终端关联。

    编程代码如下:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <sys/stat.h>
    
    
    
    void Init_Daemon()
    {
    	umask(0);
    	pid_t pid = -1;
    	if( (pid = fork()) < 0)
    	{
    		exit(0);
    	}
    	else if(pid != 0)
    	{
    		exit(0);
    	}
    	setid();
    	if((pid = fork()) < 0)
    	{
    		exit(0);
    	}
    	else if (pid != 0)
    	{
    		exit(0);
    	}
    
    
    	if(0 > chdir("/"))
    	{
    		exit(0);
    	}
    
    	struct rlimit rt;
    	if(getrlimit(RLIMIN_NOFILE,&rt) < 0)
    	{
    		exit(0);
    	}
    
    	int i = 0 ;
    	for(; i < rl.rlim_max,++i)
    	{
    		close(i);
    	}
    
    	int fd0 = open("/dev/null",O_RDWR);
    	int fd1 = dup(fd0);
    	int fd2 = dup(fd0);
    }

    若将此函数在main函数中运行,并且main函数进入睡眠状态,那么最终获得就是init进程。

     

     

     

    展开全文
  • 多进程

    2018-08-21 19:21:54
    在操作系统中,一个时间段中有进程都处于已启动运行到运行完毕之间的状态。但同一时刻只能运行一个进程。在这个时间段中,cpu给每一个进程,分配一个时间轮片。 3,进程地址空间与MMU CPU:预取器,...

    一,进程相关的概念

    1,程序与进程

    程序:是编译好的二进制文件,在磁盘上。不占用系统资源(cpu、内存、打开的文件、设备、锁....)

    进程:进程是活跃的程序,占用系统资源。

    2,并发

    在操作系统中,一个时间段中有多个进程都处于已启动运行到运行完毕之间的状态。但同一时刻只能运行一个进程。在这个时间段中,cpu给每一个进程,分配一个时间轮片。

    3,进程地址空间与MMU

    CPU:预取器,译码器,算逻单元,寄存器堆,MMU。。。。

    MMU在CPU内作用有两点:

    • 使虚拟内存映射到物理内存
    • 设置修改内存访问级别

    4,进程控制块(PCB)

    linux内核的进程控制块是task_struct结构体。

    /usr/src/linux-headers-3.16.0-30/include/linux/sched.h文件中可以查看struct task_struct 结构体定义

    部分成员:

    * 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。

    * 进程的状态,有就绪、运行、挂起、停止等状态。

    * 进程切换时需要保存和恢复的一些CPU寄存器。

    * 描述虚拟地址空间的信息。

    * 描述控制终端的信息。

    * 当前工作目录(Current Working Directory)。

    * umask掩码。

    * 文件描述符表,包含很多指向file结构体的指针。

    * 和信号相关的信息。阻塞信号集(信号屏蔽字),未决信号集。

    * 用户id和组id。

    * 会话(Session)和进程组。

    * 进程可以使用的资源上限(Resource Limit)。

    5,进程状态

    有三态模型和五态模型

    就绪态:当进程已分配到除CPU以外所有必要的资源,只要获取CPU就可以执行

    执行态:占用CPU,正在执行

    阻塞态:正在执行过程中,由于等待某个事件而无法执行,等待除CPU以外的资源而阻塞,此时放弃CPU。

    新建态和终止态

    6,常见环境变量

    环境变量:是指在操作系统中用来指定操作系统运行环境的一些参数。每个进程有一套不同的环境变量。

    PATH:可执行文件的搜索路径

    SHELL:当前shell类型

    HOME:当前用户主目录的路径

    TERM(term):当前终端类型,在图形界面终端下它的值通常是xterm

    LANG(lang):语言和locale,决定了字符编码以及时间、货币等信息的显示格式

    1,getenv函数:获取环境变量值

    char *getenv(const char *name); 成功:返回环境变量的值;失败:NULL (name不存在)

    2,setenv函数:设置环境变量的值

    int setenv(const char *name, const char *value, int overwrite);   成功:0;失败:-1

    参数overwrite取值: 1:覆盖原环境变量

    0:不覆盖。(该参数常用于设置新环境变量,如:ABC = haha-day-night)

    3,unsetenv函数:删除环境变量name的定义

    int unsetenv(const char *name); 成功:0;失败:-1

    注意事项:name不存在仍返回0(成功),当name命名为"ABC="时则会出错。

     

    二,进程控制原语

    1,fork函数

    #include <unistd.h>

    pid_t fork(void);

    pid_t :有符号整数

    返回值:-1 失败 返回成功:父进程返回子进程PID,子进程返回0。

    注意并不是fork函数有两个返回值,而是fork后变为两个。

    功能:创建一个子进程

    如果想用for循环创建n个子进程,这样会创建出2^n -1子进程。除非在子进程中break

    2,getpid函数

    #include <sys/types.h>

    #include <unistd.h>

    pid_t getpid(void);

    功能:获取当前进程ID

    3,getppid函数

    #include <sys/types.h>

    #include <unistd.h>

    pid_t getppid(void);

    功能:获取当前进程的父进程ID

    4,getuid函数

    #include <unistd.h>

    #include <sys/types.h>

    uid_t getuid(void);

    功能:获取当前进程实际用户ID

    5,geteuid函数

    #include <unistd.h>

    #include <sys/types.h>

    uid_t geteuid(void);

    功能:获取当前进程有效用户ID

    6,getgid函数

    #include <unistd.h>

    #include <sys/types.h>

    gid_t getgid(void);

    功能:获取当前进程使用用户组ID

    7,getegid函数

    #include <unistd.h>

    #include <sys/types.h>

    gid_t getegid(void);

    获取当前进程有效用户组ID

     

    8,wait函数

    #include <sys/wait.h>

    pid_t wait(int *stat_loc);

    stat_loc:进程退出状态,传出参数

    返回值:成功是子进程ID,失败是-1(没有子进程)

    功能: ① 阻塞等待子进程退出

    ② 回收子进程残留资源

    ③ 获取子进程结束状态(退出原因)。

    1. WIFEXITED(status) 为非0 → 进程正常结束

    WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)

    2. WIFSIGNALED(status) 为非0 → 进程异常终止

    WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。

    *3. WIFSTOPPED(status) 为非0 → 进程处于暂停状态

    WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。

    WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行

    用这些宏函数来获取退出状态值(正常时return exit指定的值,异常时是一些信号值

    9,waitpid函数

    #include <sys/wait.h>

    pid_t waitpid(pid_t pid, int *stat_loc, int options);

    pid:> 0 回收指定ID的子进程

            -1 回收任意子进程(相当于wait)waitpid(-1,NULL,0)==wait(NULL)

            0 回收和当前调用waitpid一个组的所有子进程

           -1 回收指定进程组内的任意子进程

    options:为0时,是阻塞模式,为WNOHANG是非阻塞

    返回值:成功是子进程ID,失败是-1(没有子进程)当options参数是WNOHANG时,返回0表示要等待的子进程在运行中。

    注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。

    三,进程共享

    刚fork之后:

    父子相同处: 全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式...

    父子不同处: 1.进程ID   2.fork返回值   3.父进程ID    4.进程运行时间    5.闹钟(定时器)   6.未决信号集7,父进程的锁

    似乎,子进程复制了父进程0-3G用户空间内容,以及父进程的PCB,但pid不同。但是 现在实际并不是这样,父子进程遵循读时共享,写时复制(针对物理地址来说)。写时才复制物理空间

    父子进程一定共享的是:1. 文件描述符

                                            2. mmap建立的映射区

    GDB调试:默认是跟踪父进程

    set follow-fork-mode child 命令设置gdb在fork之后跟踪子进程。

    set follow-fork-mode parent 设置跟踪父进程。

    注意,一定要在fork函数调用之前设置才有效。

    四,exec函数族

    调用exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。但并没有创建新的进程,进程ID没变

    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 execve(const char *path, char *const argv[], char *const envp[]);

    成功无返回,失败返回-1

    参数都要以NULL结束。

    execlp("ls", "ls", "-l", "-F", NULL);      使用程序名在PATH中搜索。

    execl("/bin/ls", "ls", "-l", "-F", NULL);    使用参数1给出的绝对路径搜索。

    记忆:

    l (list) 命令行参数列表

    p (path) 搜素file时使用path变量

    v (vector) 使用命令行参数数组

    e (environment) 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量

    通常我们直接在exec函数调用后直接调用perror()和exit(),无需if判断。

    execve只有它是系统调用。

     

    五,孤儿进程与僵尸进程

    孤儿进程:父进程先于子进程结束,此时子进程称为孤儿进程。但init进程会成为子进程的父进程。并为他收尸

    僵尸进程:子进程进程终止,父进程尚未回收(在循环),子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。父进程天生就要为子进程收尸,子进程PCB中信息决定的。

    当子进程终止时,内核给父进程产生一个SIGCHID的信号,不过父进程没有捕获此信号,而该信号的默认行为就是忽略。

    怎么回收僵尸进程?

    • 父进程通过调用wait或waitpid等待子进程结束并回收残余资源
    • 父进程很忙,可以扑捉SIG_CHLD信号,在扑捉函数中调用wait函数
    • 如果父进程不关心子进程什么时候结束,那么可以用signal(SIG_CHLD,SIG_IGN)通知内核,自己对子进程结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号
    • fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出。那么孙进程是孤儿进程,会被init接管,孙进程结束后,init会回收。不过子进程回收还要自己做。

     

     

     

     

    展开全文
  • 多进程详细讲解

    千次阅读 2018-08-18 19:48:32
    一、什么是多进程 相信看过我其他博客的同学已经对多线程和多进程有一个简单的了解了,下面我们简单说一下多进程。我们知道在进行较多的I/O操作时候,比如socket server之类的可以用到多线程,那么什么时候用多进程...

    一、什么是多进程

    相信看过我其他博客的同学已经对多线程和多进程有一个简单的了解了,下面我们简单说一下多进程。我们知道在进行较多的I/O操作时候,比如socket server之类的可以用到多线程,那么什么时候用多进程呢?我们在进行大量的密集运算时候就要用到多进程。下面我们讲解一下多进程的相关知识:

    (1)启动多进程,并在多进程中启动多线程

    #启动多进程
    import multiprocessing  #多进程
    import time,threading   #多线程
    
    def thread_run():
        print(threading.get_ident())   #打印当前线程ID
    
    def f(name):
        time.sleep(2)
        print('hello',name)
        t=threading.Thread(target= thread_run,) #在多进程调用的函数中创建一个多线程
        t.start()
    
    if __name__ == '__main__': #区分主动执行脚本还是从别的代码里导入,如果主动执行下面的就执行(在window中需要加入这句话)
    
        for i in range(10): #启动10个多进程
            p=multiprocessing.Process(target=f,args= ('我是%s'%i,))
            p.start()
            p.join()

    执行之后会启动10个多进程,每个多进程中都会启动一个多线程,并打印该线程的id,结果如下:
    这里写图片描述


    (2)每一个子进程都是由父进程启动的

    我们需要知道,每一个子进程都是由父进程启动的。下面我们来通过获取进程id的方式来证明一下:

    #我们这里父进程是:pycharm本身   由pycharm启动了子进程
    from multiprocessing import Process
    import os
    
    def info(title):
        print(title)
        print('module name:',__name__)   #获取__name__名称
        print('parent process:',os.getppid())  #得到父进程id
        print('process id:',os.getpid())      #得到自己id
        print('\n\n')
    
    def f():
        info('\033[31;1mfunction f\033[0m')   #子进程调用info()
    
    
    if __name__ == '__main__':
        info('\033[32;1mmain process line\033[0m')   #父进程调用info()
        p=Process(target= f,)  #自动多进程
        p.start()
        p.join()

    我们分别用父进程和子进程来调用函数info(),打印自己的和父进程的id,结果如下:
    这里写图片描述
    观察一下,父进程是黄色的,它的父进程id是16624,这个是pycharm本身,它的id是13624,子进程是红色的,它的父进程id是13624,也就父进程,它本身的id是12444,所以可以说是父线程创建了子线程。


    (3)进程间的通信

    大家都知道一个进程内的线程之间可以进行数据通信,但是两个进程不能直接通信,就比如我们不能利用腾讯视频来买淘宝的东西,那么我们怎么才能实现进程之间的数据传递和数据修改呢??
    下面我简单介绍一下3个方法来实现进程间的数据通信:

    1. Queues:实现两个进程之间的数据传递
    2. Pipes:管道形式数据传递,建立一个管道通讯
    3. Managers:实现两个进程的数据共享(可以修改数据,不仅仅是传递数据)

    先说一下队列方法(Queues):

    from multiprocessing import Process ,Queue #导入Queue模块
    
    def f(q1):
        q1.put(['hello',42]) #在子进程中把数据['hello',42]放入队列中
    
    if __name__ == '__main__':
        q=Queue()  #启动一个进程的队列
        p=Process(target= f,args= (q,))  #在启动子进程时候,将进程的队列q赋值进去
        p.start()
        print(q.get())     #父进程从队列中取数据,实现两个进程之间的数据通讯
        p.join()

    结果是:
    这里写图片描述


    然后介绍一下Pipes方法,就是在进程之间生成一个管道进行数据传递。

    from multiprocessing import Process ,Pipe  #导入Pipe模块
    
    def f1(conn):  
        conn.send([42,'hello'])    #子进程发送数据
        print('from parent:',conn.recv()) #子进程接收父进程的数据
        conn.close()
    
    if __name__ =='__main__':
        parent_conn,child_conn=Pipe()   #生成管道的两头,一个父进程一个子进程
        p=Process(target= f1,args=(child_conn,)) #创建一个子进程
        p.start()
        print(parent_conn.recv())   #父进程这里接收子进程发送的数据
        parent_conn.send('你好')    #父进程发送数据给子进程
        p.join()

    结果是:
    这里写图片描述


    最后我们说明Managers这个方法,可以进行进程之间的数据修改。

    from multiprocessing import Process ,Manager #导入Manager方法
    import os
    
    def f2(d,l):
        d[os.getpid()]=os.getpid() #10个进程都在修改字典,键和值都为每个子进程的id
        l.append(os.getpid())  #10个进程都在扩充列表
        print(l)
    
    if __name__ == '__main__':
        with Manager() as manager:
            d=manager.dict() #manager中的生成一个可在多个进程中传递、共享数据的字典
    
            l=manager.list(range(5))  #manager中的生成一个可在多个进程中传递、共享数据的列表
            p_list=[]
            for i in range(10): #创建10个子进程
                p=Process(target=f2,args= (d,l))
                p.start()
                p_list.append(p)
            for res in p_list :  #等待所有进程执行完毕
                res.join()
            print(d)
            print(l)

    结果是:
    这里写图片描述
    可以发现进程之间可以进行数据修改。


    (4)进程池

    进程池是防止启动进程过多,系统负荷大,而设置的。看一个例子:

    from multiprocessing import Process,Pool  #导入进程池
    import time,os
    
    def Foo(i):
        time.sleep(2)
        print('到了2s')
        return i+100
    def Bar(arg):
        print('结果:',arg)
    
    if __name__  == '__main__':  
        pool=Pool(processes= 5)  #允许进程池同时放入5个进程
    
        for i in range(10):  #10个进程都启动 但是一次只能运行5个
            #pool.apply(func= Foo,args=(i,))  #串行执行进程,一次执行1个进程
            pool.apply_async(func= Foo,args=(i,),callback= Bar) #并行执行进程,一次5个,callback回调 Foo执行完就会执行Bar
        print('end')
        pool.close()
        pool.join() #等待进程池中的进程执行完毕  必须先close()  在join()

    结果是:
    这里写图片描述
    可以利用进程池来限制每次执行进程的数量,防止电脑负荷过大。

    展开全文
  • 线程、进程 的创建

    千次阅读 2014-05-10 15:12:22
    线程、进程 的创建

    线程、进程 的创建

    创建线程。

    //简单多线程示例 
    #include 
    #include 
    using namespace std;
    DWORD WINAPI f_hello(LPVOID );
    DWORD WINAPI f_hi(LPVOID );//形参必须是这个样子 
    
    int main(int argc, char *argv[])
    {
    	HANDLE h_hello,h_hi;
    	h_hello=CreateThread(NULL,0,f_hello,NULL,0,NULL);//hello
    	h_hi=CreateThread(NULL,0,f_hi,NULL,0,NULL);//hi
    	CloseHandle(h_hello);//只是关闭句柄,线程运行不受影响 
    	CloseHandle(h_hi);
    	getchar();//不加getchar()进程会直接结束,看不到输出。因为线程创建函数是异步的。 
    	return 0;
    }
    DWORD WINAPI f_hello(LPVOID lpParamter){
    	while(true){Sleep(1000);cout<<"hello\n";}
    	ExitThread(0);
    }
    DWORD WINAPI f_hi(LPVOID lpParamter){
    		while(true){Sleep(1000);cout<<"hi\n";}
    	ExitThread(0);
    }
    
    //交替输出hello hi
    

    创建进程。

    //create_process
    #include
    #include
    
    char szCommandLine[]="notepad";//系统自有程序,加不加'.exe'无影响 
    STARTUPINFO si={sizeof(si)};//STARTUPINFO 结构体的第一个参数是自身大小 
    PROCESS_INFORMATION pi;
    void f_create_1(){
      si.dwFlags=STARTF_USESHOWWINDOW;//指定wShowWindow成员有效
      si.wShowWindow=TRUE;//此成员设为TRUE的话则显示新建进程的主窗口
      BOOL bRet=CreateProcess(
        NULL,//不在此指定可执行文件的文件名
    	szCommandLine,//命令行参数,相当于从cmd窗口打开 notepad
    	NULL,//默认进程安全性
    	NULL,//默认进程安全性
    	TRUE,//指定当前进程内句柄可以被子进程继承
        CREATE_NEW_CONSOLE,//为新进程创建一个新的控制台窗口
        NULL,//使用本进程的环境变量
        NULL,//使用本进程的驱动器和目录
        &si,
        &pi);
      //不使用的句柄最好关掉
      CloseHandle(pi.hThread);
      CloseHandle(pi.hProcess);
      printf("新进程的ID号:%d\n",pi.dwProcessId);
      printf("新进程的主线程ID号:%d\n",pi.dwThreadId);
    } 
    void f_create_2(){
      si.dwFlags=STARTF_USESHOWWINDOW;//指定wShowWindow成员有效
      si.wShowWindow=TRUE;//此成员设为TRUE的话则显示新建进程的主窗口
      BOOL bRet=CreateProcess(
        "D:\\high.exe",//程序名字,当前目录下的程序,或加上路径,须有.exe后缀 
    	NULL,//命令行参数
    	NULL,//默认进程安全性
    	NULL,//默认进程安全性
    	TRUE,//指定当前进程内句柄可以被子进程继承
        CREATE_NEW_CONSOLE,//为新进程创建一个新的控制台窗口
        NULL,//使用本进程的环境变量
        NULL,//使用本进程的驱动器和目录
        &si,
        &pi);
      //不使用的句柄最好关掉
      CloseHandle(pi.hThread);
      CloseHandle(pi.hProcess);
      printf("新进程的ID号:%d\n",pi.dwProcessId);
      printf("新进程的主线程ID号:%d\n",pi.dwThreadId);
    } 
    
    int main(int argc,char*argv[]){
      f_create_1();
      f_create_2();
      return 0;
    }
    
    该程序效果见下。
    展开全文
  • C/C++多进程-1

    万次阅读 2018-09-19 14:46:14
    C/C++进程与线程 程序运行基础部分  1、时钟中断:即为道程序设计模型的理论基础。 并发时,任意进程在执行期间都不希望放弃cpu。因此系统需要一种强制让进程让出cpu资源的手段。时钟中断有硬件基础作为保障,...
  • 多进程实现

    2020-10-25 18:59:13
    一、进程三种状态 1.就绪状态(Ready) 当进程已分配到除CPU以外的所有必须的资源,只要获得处理机便可以...引起进程阻塞的事件有很种,例如,等待I/O完成、申请缓存区不能满足、等待条件(信号)等。 4. 状态转换 处
  • 线程是什么?要理解这个概念,须要先了解一下操作系统的一些相关概念。大部分操作系统(如...这样每个任务都能得到执行,由于CPU的执行效率非常高,时间片非常短,在各个任务之间快速地切换,给人的感觉就是个任
  • 多线程还是多进程的选择及区别

    万次阅读 多人点赞 2018-12-17 21:29:30
    本人博客将陆续迁至https://dpjeep.com 欢迎造访 ...感觉这篇博文写的很棒,特此转载了   鱼还是熊掌:浅谈多进程多线程的选择 关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配...
  • golang多进程测试代码

    万次阅读 2019-01-23 10:10:31
    package main import ( "fmt" "runtime" ) func test(c chan bool, n int) { x := 0 for i := 0; i &lt; 1000000000; i++ { x += i } println(n, x) ...runtime.GOM...
  • python多进程原理及其实现

    千次阅读 2019-03-21 11:02:25
    1 进程的基本概念 ...进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。 进程的过程: 创建, 就绪, 运行 ,阻塞, ...
  • Python多进程和多线程(跑满CPU)

    万次阅读 2019-09-17 18:39:37
    Python多进程和多线程(跑满CPU) 概念 任务可以理解为进程(process),如打开一个word就是启动一个word进程。在一个word进程之中不只是进行打字输入,还需要拼写检查、打印等子任务,我们可以把进程中的这些子...
  • Python之多进程和多线程详解

    万次阅读 多人点赞 2018-10-16 18:02:56
    1.进程的概念 一个CPU的时候运行,轮询调度实现并发执行 CPU运行机制: 计算机程序:存储在磁盘上的可执行二进制(或其他类型)文件。 只有把它们加载到内存中,并被操作系统调用它们才会拥有其自己的生命周期。...
  • 正常情况下,一个apk启动后只会运行在一个进程中,其进程名为apk的包名,所有的组件都会在这个进程中运行,以下为DDMS的进程截屏: com.biyou.multiprocess为进程名,也是apk的包名,  但是如果需要将某些组件(如...
  • 多线程和多进程的区别(小结)

    万次阅读 多人点赞 2011-08-15 15:54:54
    很想写点关于多进程和多线程的东西,我确实很爱他们。但是每每想动手写点关于他们的东西,却总是求全心理作祟,始终动不了手。今天终于下了决心,写点东西,以后可以再修修补补也无妨。 一.为何需要多进程(或者多...
  • Android 多进程使用场景

    千次阅读 2019-07-23 12:06:09
    推荐资源站:https://zhimalier.com/ 本文章原作者已授权转载 原文地址... 在上一篇《Android 线程介绍》中,我们大概了解了一下Android中的进程的概念以及其生命周期,另外还有Low Memory Kill...
  • Android 多进程的基础使用及优缺点

    千次阅读 2019-07-08 18:12:18
    前言说起进程,不得不说说进程和线程之前的关系。在操作系统角度描述,线程是CPU调度的最小...我们可以使用多进程分担主进程压力以免因资源消耗过大被crash掉,另外多进程相互监听可以唤醒,使应用程序长期驻守后...
  • Python多进程之进程池

    千次阅读 2017-04-05 11:28:16
    当我们有并行处理需求的时候,可以采用多进程迂回地解决。如果要在主进程中启动大量的子进程,可以用进程池的方式批量创建子进程。 首先,创建一个进程池子,然后使用apply_async()方法将子进程加入到进程池中。...
  • python 多进程并发与多线程并发总结

    万次阅读 2015-05-16 21:06:28
    本文对python支持的几种并发方式——多进程并发与多线程并发进行简单的总结。
  • python多进程技术

    千次阅读 2019-03-08 20:09:32
    进程的概念 可执行的代码就叫程序。 正在运行着的代码+需要的一些资源就是进程。 例子:QQ没打开的时候是程序,打开了之后是进程。 fork fork()调用一次,返回两次。从返回处开始,父子进程的代码就是一样的了。 ...
  • 多线程和多进程模型的选用

    千次阅读 2016-01-04 14:18:32
    多线程和多进程模型的选用 这里的线程指通过linux的pthread_create而产生的原生线程,线程资源很宝贵,能被操作系统的任务调度器看见的(不是python gevent、go gorouine里的概念);  我们讨论以下两种模型; ...
1 2 3 4 5 ... 20
收藏数 1,608,128
精华内容 643,251
关键字:

多进程