精华内容
下载资源
问答
  • 关于Windows创建进程过程

    千次阅读 2017-11-21 19:38:45
    当我们通过explorer.exe运行一个程序时,explorer.exe会调用CreateProcess函数请求系统为这个程序创建进程。当然,其它程序也可以调用CreateProcess函数创建进程。 系统在为进程分配内部资源,建立独立的地址空间...

    1. 程序的启动

    当我们通过explorer.exe运行一个程序时,explorer.exe会调用CreateProcess函数请求系统为这个程序创建进程。当然,其它程序也可以调用CreateProcess函数创建进程。

    系统在为进程分配内部资源,建立独立的地址空间后,会为进程创建一个主线程。我们可以把进程看作单位,把线程看作员工。进程拥有资源,但真正在CPU上运行和调度的是线程。系统以挂起状态创建主线程,即主线程创建好,不会立即运行,而是等待系统调度。系统向Win32子系统的管理员csrss.exe登记新创建的进程和线程。登记结束后,系统通知挂起的主线程可以运行,新程序才开始运行。

    这时,在创建进程中CreateProcess函数返回;在被创建进程中,主线程在完成最后的初始化后进入程序的入口函数(Entry-point)。创建进程与被创建进程在各自的地址空间独立运行。这时,即使我们结束创建进程,也不会影响被创建进程。


    2. 程序的执行

    可执行文件(PE文件)的文件头结构包含入口函数的地址。入口函数一般是Windows在运行时库中提供的,我们在编译时可以根据程序类型设定。在VC中编译、运行程序的小知识点讨论了Entry-point,读者可以参考。

    入口函数前的过程可以被看作程序的装载过程。在装载时,系统已经做过全局和静态变量(在编译时可以确定地址)的初始化,有初值的全局变量拥有了它们的初值,没有初值的变量被设为0,我们可以在入口函数处设置断点确认这一点。

    进入入口函数后,程序继续运行环境的建立,例如调用所有全局对象的构造函数(很典型的是单文档的 theApp)。在一切就绪后,程序调用我们提供的主函数。主函数名是入口函数决定的,例如main或WinMain。如果我们没有提供入口函数要求的主函数,编译时就会产生链接错误。


    3. 进程和线程

    我们通常把存储介质(例如硬盘)上的可执行文件称作程序。程序被装载、运行后就成为进程。系统会为每个进程创建一个主线程,主线程通过入口函数进入我们提供的主函数。我们可以在程序中创建其它线程。

    线程可以创建一个或多个窗口,也可以不创建窗口。系统会为有窗口的线程建立消息队列。有消息队列的线程就可以接收消息,例如我们可以用PostThreadMessage函数向线程发送消息。

    没有窗口的线程只要调用了PeekMessage或GetMessage,系统也会为它创建消息队列。


    展开全文
  • linux进程创造 - 创建进程API及过程

    千次阅读 2016-11-20 00:56:20
    1. 创建进程函数API1.1 创建进程fork()fork的翻译为“叉子,分叉”,其实在unix编程中,我们来创建进程的时候是深有体会的,感觉创建一个进程就像是走到了一个岔路口,父进程和子进程在叉路口分道扬镳,所以我想这...

    1. 创建进程函数API


    1.1 创建进程fork()

    fork的翻译为“叉子,分叉”,其实在unix编程中,我们来创建进程的时候是深有体会的,感觉创建一个进程就像是走到了一个岔路口,父进程和子进程在叉路口分道扬镳,所以我想这就是前辈为什么要用fork来表示创建一个进程的缘由吧。

    通过fork(),除了task_struct和堆栈,子进程和父进程共享所有的资源,相当于复制了一个父进程,但是由于linux采用了写时复制技术,复制工作不是立即就执行,提高了效率。在unix编程中,调用fork实际上相当于创建了一个进程。

    (kernel/fork.c)

    SYSCALL_DEFINE0(fork)
    {
    #ifdef CONFIG_MMU
        return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
    #else
        /* can not support in nommu mode */
        return -EINVAL;
    #endif
    }

    1.2 创建进程vfork()

    vfork类似于fork,但并不创建父进程数据的副本,相反,父子进程之间共享数据,这节省了大量CPU时间。

    vfork设计用于子进程形成后立即执行execve加载新程序的情形。在子进程退出或开始新程序之前,内核保证父进程处于阻塞状态。但是由于fork使用了写时复制技术,vfork速度方面不再有优势,因此应该避免使用它。

    (kernel/fork.c)

    SYSCALL_DEFINE0(vfork)
    {
        return _do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
                0, NULL, NULL, 0);
    }

    1.3 创建线程clone()

    clone翻译为“克隆”,从字面理解就是照着父进程的样子重新生成一个子进程,但是子进程是一个新的个体,和父进程已经少了许多关系。

    clone产生线程,可以对父子进程之间的共享、复制进行精确控制。

    (kernel/fork.c)

    #ifdef CONFIG_CLONE_BACKWARDS
    SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
             int __user *, parent_tidptr,
             unsigned long, tls,
             int __user *, child_tidptr)
    #elif defined(CONFIG_CLONE_BACKWARDS2)
    SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
             int __user *, parent_tidptr,
             int __user *, child_tidptr,
             unsigned long, tls)
    #elif defined(CONFIG_CLONE_BACKWARDS3)
    SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
            int, stack_size,
            int __user *, parent_tidptr,
            int __user *, child_tidptr,
            unsigned long, tls)
    #else
    SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
             int __user *, parent_tidptr,
             int __user *, child_tidptr,
             unsigned long, tls)
    #endif
    {
        return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);
    }

    1.4 进程创建部分标志的含义

    flagsdescription
    CLONE_VM共享内存描述符和所有的页表
    CLONE_FS共享根目录和当前工作目录所在的表
    CLONE_FILES共享打开文件表
    CLONE_SIGHAND共享信号处理程序的表、阻塞信号表和挂起信号表
    CLONE_VFORKvfork使用的标志
    CLONE_PARENT设置子进程的父进程为调用进程的父进程
    CLONE_THREAD创建线程使用的标志
    CLONE_PARENT_SETTID把子进程的PID写入有ptid参数所指向的父进程的用户态变量
    CLONE_CHILD_SETTID把子进程的PID写入有ctid参数所指向的子进程的用户态变量
    CLONE_NEWNS当clone需要自己的命名空间时设置这个标志

    2. _do_fork


    上述创建进程的API最后调用的函数都是_do_fork,下面来介绍此函数的工作

    (kernel/fork.c)

    
    long _do_fork(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr,unsigned long tls)
    {
        struct task_struct *p;
        int trace = 0;
        long nr;
    
        /*
         * Determine whether and which event to report to ptracer.  When
         * called from kernel_thread or CLONE_UNTRACED is explicitly
         * requested, no event is reported; otherwise, report if the event
         * for the type of forking is enabled.
         */
        if (!(clone_flags & CLONE_UNTRACED)) {
            if (clone_flags & CLONE_VFORK)
                trace = PTRACE_EVENT_VFORK;
            else if ((clone_flags & CSIGNAL) != SIGCHLD)
                trace = PTRACE_EVENT_CLONE;
            else
                trace = PTRACE_EVENT_FORK;
    
            if (likely(!ptrace_event_enabled(current, trace)))
                trace = 0;
        }
    
        p = copy_process(clone_flags, stack_start, stack_size,----------------复制父进程的一些数据
                 child_tidptr, NULL, trace, tls);
        /*
         * Do this prior waking up the new thread - the thread pointer
         * might get invalid after that point, if the thread exits quickly.
         */
        if (!IS_ERR(p)) {
            struct completion vfork;
            struct pid *pid;
    
            trace_sched_process_fork(current, p);
    
            pid = get_task_pid(p, PIDTYPE_PID);
            nr = pid_vnr(pid);
    
            if (clone_flags & CLONE_PARENT_SETTID)
                put_user(nr, parent_tidptr);
    
            if (clone_flags & CLONE_VFORK) {
                p->vfork_done = &vfork;
                init_completion(&vfork);
                get_task_struct(p);
            }
    
            wake_up_new_task(p);-----------------------------------------------使进程加入运行队列,被调度
    
            /* forking complete and child started to run, tell ptracer */
            if (unlikely(trace))
                ptrace_event_pid(trace, pid);
    
            if (clone_flags & CLONE_VFORK) {-----------------------------------如果有标志CLONE_VFORK,就等待让子进程先运行
                if (!wait_for_vfork_done(p, &vfork))
                    ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
            }
    
            put_pid(pid);
        } else {
            nr = PTR_ERR(p);
        }
        return nr;
    }

    3. copy_process


    static struct task_struct *copy_process(unsigned long clone_flags,
                        unsigned long stack_start,
                        unsigned long stack_size,
                        int __user *child_tidptr,
                        struct pid *pid,
                        int trace,
                        unsigned long tls)

    copy_process的流程图如下所示,其中代码细节部分会在文章系列的子部分详细说明:

    这里写图片描述

    change log


    datecontentlinux kernel
    2016.11.20原始写作4.6.3
    展开全文
  • 进程创建过程

    千次阅读 2019-02-25 16:07:26
    进程创建时,调用do_fork函数来创建进程,那么和调度相关的操作主要有两个,一个是sched_fork,这是对一个进程进行调度的初始化,另外一个就是wake_up_new_task,这个是把刚刚创建的子进程唤醒加入到调度器中...

    进程创建

    在进程创建时,调用do_fork函数来创建新进程,那么和调度相关的操作主要有两个,一个是sched_fork,这是对一个进程进行调度的初始化,另外一个就是wake_up_new_task,这个是把刚刚创建的子进程唤醒加入到调度器中管理。
    首先来看sched_fork函数,调用流为do_fork–>copy_process–>sched_fork。

     /*
      * fork()/clone()-time setup:
      */
     int sched_fork(unsigned long clone_flags, struct task_struct *p)
     {
         unsigned long flags;
         int cpu = get_cpu();
     
         __sched_fork(clone_flags, p);   //调度相关结构体的初始化操作函数
         /*
          * We mark the process as running here. This guarantees that
          * nobody will actually run it, and a signal or other external
          * event cannot wake it up and insert it on the runqueue either.
          */
         p->state = TASK_RUNNING;       //设置进程状态为RUNNING
     
         /*
          * Make sure we do not leak PI boosting priority to the child.
          */
         p->prio = current->normal_prio;  //设置优先级为普通优先级
     
         /*
          * Revert to default priority/policy on fork if requested.
          */
         if (unlikely(p->sched_reset_on_fork)) {
             if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
                 p->policy = SCHED_NORMAL;
                 p->static_prio = NICE_TO_PRIO(0);
                 p->rt_priority = 0;
             } else if (PRIO_TO_NICE(p->static_prio) < 0)
                 p->static_prio = NICE_TO_PRIO(0);
     
             p->prio = p->normal_prio = __normal_prio(p);
             set_load_weight(p);
     
             /*
              * We don't need the reset flag anymore after the fork. It has
              * fulfilled its duty:
              */
             p->sched_reset_on_fork = 0;     //以上这段是为了判断是否要重置调度策略
         }
     
         if (dl_prio(p->prio)) {
             put_cpu();
             return -EAGAIN;
         } else if (rt_prio(p->prio)) {
             p->sched_class = &rt_sched_class;
         } else {
             p->sched_class = &fair_sched_class;  //普通进程设置调度类为CFS调度器
         }
     
         if (p->sched_class->task_fork)
             p->sched_class->task_fork(p);  //执行调度类中的task_fork回调
     
         /*
          * The child is not yet in the pid-hash so no cgroup attach races,
          * and the cgroup is pinned to this child due to cgroup_fork()
          * is ran before sched_fork().
          *
          * Silence PROVE_RCU.
          */
         raw_spin_lock_irqsave(&p->pi_lock, flags);
         set_task_cpu(p, cpu);            //设置子进程的cpu为父进程的cpu
         raw_spin_unlock_irqrestore(&p->pi_lock, flags);
     
     #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
         if (likely(sched_info_on()))
             memset(&p->sched_info, 0, sizeof(p->sched_info));
     #endif
     #if defined(CONFIG_SMP)
         p->on_cpu = 0;
     #endif
         init_task_preempt_count(p);    //进程抢占标志初始化
     #ifdef CONFIG_SMP
         plist_node_init(&p->pushable_tasks, MAX_PRIO);
         RB_CLEAR_NODE(&p->pushable_dl_tasks);
     #endif
     
         put_cpu();
         return 0;
     }
    
    

    下面来看CFS调度器中task_fork的实现,调用流do_fork–>copy_process–>sched_fork–>task_fork_fair:

    static void task_fork_fair(struct task_struct *p)
    {
        struct cfs_rq *cfs_rq;
        struct sched_entity *se = &p->se, *curr;
        int this_cpu = smp_processor_id();
        struct rq *rq = this_rq();
        unsigned long flags;
    
        raw_spin_lock_irqsave(&rq->lock, flags);
    
        update_rq_clock(rq);
    
        cfs_rq = task_cfs_rq(current);
        curr = cfs_rq->curr;
    
        /*
         * Not only the cpu but also the task_group of the parent might have
         * been changed after parent->se.parent,cfs_rq were copied to
         * child->se.parent,cfs_rq. So call __set_task_cpu() to make those
         * of child point to valid ones.
         */
        rcu_read_lock();
        __set_task_cpu(p, this_cpu);
        rcu_read_unlock();
    
        update_curr(cfs_rq);
    
        if (curr)
            se->vruntime = curr->vruntime;
        place_entity(cfs_rq, se, 1);
    
        if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) {
            /*
             * Upon rescheduling, sched_class::put_prev_task() will place
             * 'current' within the tree based on its new key value.
             */
            swap(curr->vruntime, se->vruntime);
            resched_curr(rq);
        }
    
        se->vruntime -= cfs_rq->min_vruntime;
    
        raw_spin_unlock_irqrestore(&rq->lock, flags);
    }
    

    这个函数主要实现的是如下几个步骤:
    (1)更新runqueue clock
    (2)设置当前进程cpu为父进程的CPU
    (3)update_curr是CFS调度器中核心函数,更新父进程的sum_exec_runtime,vruntime和runqueue的min_vruntime
    (4)place_entity对于新创建的进程进行惩罚,vruntime会加上一个值,放置新创建进程恶意占有CPU

    加入运行队列(enqueue操作)

    上面介绍的就是进程创建关于调度的初始化过程,那么初始化完成后,下面就要把新的子进程加入到调度器中,涉及的函数如下do_fork–>wake_up_new_task:

     void wake_up_new_task(struct task_struct *p)
     {
         unsigned long flags;
         struct rq *rq;
     
         raw_spin_lock_irqsave(&p->pi_lock, flags);
     #ifdef CONFIG_SMP
         /*
          * Fork balancing, do it here and not earlier because:
          *  - cpus_allowed can change in the fork path
          *  - any previously selected cpu might disappear through hotplug
          */
         set_task_cpu(p, select_task_rq(p, task_cpu(p), SD_BALANCE_FORK, 0));   //子进程重新选择runqueue和cpu,相当于进行了一次负载均衡处理
     #endif
     
         /* Initialize new task's runnable average */
         init_task_runnable_average(p);                   //依据权重初始化子进程的时间片和负载贡献
         rq = __task_rq_lock(p);
         activate_task(rq, p, 0);                         //把子进程加入到runqueue,这是该函数的关键核心
         p->on_rq = TASK_ON_RQ_QUEUED;
         trace_sched_wakeup_new(p, true);
         check_preempt_curr(rq, p, WF_FORK);
     #ifdef CONFIG_SMP
         if (p->sched_class->task_woken)
             p->sched_class->task_woken(rq, p);
     #endif
         task_rq_unlock(rq, p, &flags);
     }
    
    
    void activate_task(struct rq *rq, struct task_struct *p, int flags)
    {   
        if (task_contributes_to_load(p))
            rq->nr_uninterruptible--;
        
        enqueue_task(rq, p, flags);
    }
    
    static void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
    {
        update_rq_clock(rq);
        sched_info_queued(rq, p);
        p->sched_class->enqueue_task(rq, p, flags);
    }   
    
    static void
    enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
    {
        struct cfs_rq *cfs_rq;
        struct sched_entity *se = &p->se;
    
        for_each_sched_entity(se) {
            if (se->on_rq)
                break;
            cfs_rq = cfs_rq_of(se);
            enqueue_entity(cfs_rq, se, flags);  //调度实体加入到runqueue中
    
            /*
             * end evaluation on encountering a throttled cfs_rq
             *
             * note: in the case of encountering a throttled cfs_rq we will
             * post the final h_nr_running increment below.
            */
            if (cfs_rq_throttled(cfs_rq))
                break;
            cfs_rq->h_nr_running++;
    
            flags = ENQUEUE_WAKEUP;
        }
    
        for_each_sched_entity(se) {
            cfs_rq = cfs_rq_of(se);
            cfs_rq->h_nr_running++;
    
            if (cfs_rq_throttled(cfs_rq))
                break;
    
            update_cfs_shares(cfs_rq);      //更新cfs shares
            update_entity_load_avg(se, 1);  //更新调度实体负载和runqueue负载,在实际上在上面的enqueue_entity也会执行这两步
        }
    
        if (!se) {
            update_rq_runnable_avg(rq, rq->nr_running);
            add_nr_running(rq, 1);
        }
        hrtick_update(rq);
    }
    
    static void
    enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
    {
        /*
         * Update the normalized vruntime before updating min_vruntime
         * through calling update_curr().
         */
        if (!(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_WAKING))
            se->vruntime += cfs_rq->min_vruntime;  //新创建进程加上一个min_vruntime
    
        /*
         * Update run-time statistics of the 'current'.
         */
        update_curr(cfs_rq);  //更新子进程runqueue对应的当前进程相关的时间信息和vruntime信息
        enqueue_entity_load_avg(cfs_rq, se, flags & ENQUEUE_WAKEUP);  //子进程加入到对应runqueue的负载计算中
        account_entity_enqueue(cfs_rq, se);
        update_cfs_shares(cfs_rq);
    
        if (flags & ENQUEUE_WAKEUP) {
            place_entity(cfs_rq, se, 0); //对于刚刚唤醒的进程进行补偿,vruntime减去一个值,提高优先级执行
            enqueue_sleeper(cfs_rq, se);
        }
    
        update_stats_enqueue(cfs_rq, se);
        check_spread(cfs_rq, se);
        if (se != cfs_rq->curr)
            __enqueue_entity(cfs_rq, se); //加入到runqueue中的rb tree的处理
        se->on_rq = 1;
    
        if (cfs_rq->nr_running == 1) {
            list_add_leaf_cfs_rq(cfs_rq);
            check_enqueue_throttle(cfs_rq);
        }
    }
    
    

    经历了以上这些操作以后,一个进程的创建到加入runqueue的过程就完成了,后续该进程就开始接受CFS调度器的调度了。

    展开全文
  • Windows操作系统下创建进程过程

    千次阅读 2013-11-20 16:26:13
    进程(Process)是具有一定独立功能的程序关于某个数据集合上...它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消,反映了一个程序在一定的数据集上运行的全部动态过程。  线程
    进程(Process)是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体。而进程则不同,它是程序在某个数据集上的执行,是一个动态实体。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消,反映了一个程序在一定的数据集上运行的全部动态过程。
    
      线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位。线程不能够独立执行,必须依存在进程中,由进程提供多个线程执行控制。从内核角度讲线程是活动体对象,而进程只是一组静态的对象集,进程必须至少拥有一个活动线程才能维持运转。


    当某个应用程序调用一个创建进程的函数比如CreateProcess或者用户执行某一个程序(其实windows下用户执行一般普通程序是由explorer.exe调用CreateProcess来完成),操作系统把这个过程分成以下步骤来完成:
    1.打开将要在该进程中执行的映像文件。
    2.创建Windows执行体进程对象。
    3.创建初始线程(栈、堆执行环境初始化及执行线程体对象)。
    4.通知Windows子系统新进程创建了(子系统是操作系统的一部分它是一个协助操作系统内核管理用户态/客户方的一个子系统具体的进程为Csrss.exe)。
    5.开始执行初始线程(如果创建时候指定了线程的CREATE_SUSPENDED状态则线程暂时挂起不执行)。
    6.在新进程和线程环境中完成地址空间的初始化(比如加载必须的DLL和库),然后开始到进程入口执行。
    到这里操作系统完成一个新进程的创建过程。下面来看下具体每一步操作系统所做的工作:
    1.打开将要在该进程中执行的映像文件。
    首先操作系统找到执行的Windows映像然后创建一个内存区对象,以便后面将它映射到新的进程地址空间中。


    2.创建Windows执行体进程对象。
    接下来操作系统调用内部的系统函数NtCreateProcess来创建一个Windwos执行体进程对象。具体步骤是:
    (1)建立EPROCESS
    *分配并初始化EPROCESS结构块
    *从父进程处继承得到进程的亲和性掩码
    *分配进程的最大最小工作集尺(由两个参数决定PsMinimumWorkingSet PsMaximumWorkingSet)
    *降新进程的配额块设置为父进程配额块地址,并递增父进程配额块的引用计数
    *继承Windows的设备名字空间
    *将父进程进程ID保存在新进程对象的InheritedFormUniqueProcessId中
    *创建该进程的主访问令牌
    *初始化进程句柄表
    *将新进程的退出状态设置为STATUS_PENDING


    (2)创建初始的进程地址空间
    *在适当的页表中创建页表项,以映射初始页面
    *从MmresidentAvailablePage算出进程工作集大小
    *系统空间的非换页部分和系统缓存的页表被映射到进程


    (3)初始化内核进程块KPROCESS
    (4)结束进程地址空间的创建过程
    (5)建立PEB
    (6)完成执行体进程对象的创建过程


    3.创建初始线程(栈、堆执行环境初始化及执行线程体对象)。
    这时候Windows执行体进程对象已经完全建立完成,但它还没有线程所以无法执行,接下来系统调用NtCreateThread来创建一个挂起的新线程它就是进程的主线程体。


    4.通知Windows子系统新进程创建了(子系统是操作系统的一部分它是一个协助操作系统内核管理用户态/客户方的一个子系统具体的进程为Csrss.exe)。接下来操作系统通过客户态(Kernel32.dll)给Windows子系统(Csrss)发送一个新进程线程创建的数据消息,让子系统建立自己的进程线程管理块。当Csrss接收到该消息时候执行下面的处理:
    *复制一份该进程和线程句柄
    *设置进程优先级
    *分配Csrss进程块
    *把新进程的异常处理端口绑定到Csrss中,这样当该进程发生异常时,Csrss将会接收到异常消息
    *分配和初始化Csrss线程块
    *把线程插入到进程的线程列表中
    *把进程插入到Csrss的线程列表中
    *显示进程启动光标


    5.开始执行初始线程(如果创建时候指定了线程的CREATE_SUSPENDED状态则线程暂时挂起不执行)。到这里进程环境已经建立完毕进程中开始创建的主线程到这里获得执行权开始执行线程。


    6.在新进程和线程环境中完成地址空间的初始化(比如加载必须的DLL和库),然后开始到进程入口执行。
    到这步实质是调用ldrInitializeThunk来初始化加载器,堆管理器NLS表TLS数组以及临界区结构,并且加载任何必须要的DLL并且用


    DLL_PROCESS_ATTACH功能代码来调用各DLL入口点,最后当加载器初始化例程返回到用户模式APC分发器时进程映像开始在用户模式下执行,然后它调用线程启动函数开始执行。


    到这里操作系统完成了所有的创建工作,我们写的程序就这样被操作系统调用运行起来了。
    展开全文
  • 进程创建过程

    千次阅读 2019-05-18 17:47:47
    所有的进程都是由别的进程创建出来的,用鼠标双击运行一个程序的时候,实际上是由...进程创建过程: 映射EXE文件 创建内核对象EPROCESS(一个进程对应一个EPROCESS) 映射系统DLL(ntdll.dll) 创建线程内核对象ET...
  • LInux进程创建过程

    千次阅读 2019-04-15 22:58:41
    传统的fork系统调用直接把所有的资源复制给新创建进程,但是这种实现过于简单,效率低下,因为并不支持拷贝数据的共享。 更糟的是如果新进程打算立即执行一个新的映像那么所有的拷贝都将前功尽弃。 Linux下面的...
  • 创建进程,等待进程,进程终止
  • Java创建进程

    万次阅读 2013-09-26 14:44:25
    Java创建进程  1 进程的概念 1  1.1 进程的概念 1  1.2 进程的特征 1  1.3 进程与线程区别 1  2 进程的创建 1  2.1 JAVA进程的创建 1  2.1.1 ProcessBuilder 2  2.1.2 Runtime 3  2.1.3 ...
  • 创建进程的方法

    千次阅读 2019-03-12 21:52:29
    今天学习了创建进程的方法,有两种方法。 方法一:Process([group[,target[,name[,args[,kwargs]]]]) target:进程所调用的对象,一般情况跟函数名,记得不要有括号。 args:调用对象的位置参数,是一个元组。...
  • 创建进程的步骤

    千次阅读 2018-07-02 14:22:00
    创建进程所必需的步骤: 1,申请空白PCB(进程控制块); 2,为新进程分派资源; 3,初始化PCB; 4,将新进程插入就绪队列; 转载于:https://www.cnblogs.com/westlife-11358/p/9253612.html...
  • linux创建进程过程

    千次阅读 2015-05-29 22:08:57
    进程中调用fork()来创建进程。fork()进一步调用do_fork(),要完成任务有: 1. 在内存空间为新进程分配任务结构体使用的空间,然后把当前进程的任务结构体的所有内容拷贝到子进程的任务结构体中; 2. 为新进程...
  • 多进程编程---创建进程 头文件:#include<unistd.h> 创建一个新进程 :pid_t fork(void) 如果出错返回-1 fork 调用一次,两次返回,原来的进程返回新进程的pid(父进程) 新进程中返回0(子进程) ...
  • linux进程创建过程与原理

    千次阅读 2012-07-01 15:28:25
    linux创建进程过程。 原文链接:http://blog.21ic.com/user1/8252/archives/2012/89761.html 系统允许一个进程创建进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。整个linux...
  • Zygote进程创建过程(Android 8.1)

    万次阅读 2019-08-13 16:10:29
    本篇文章的内容中,我将要给大家介绍Android开发中最长见到的一个底层进程——...它的启动过程从init进程启动开始,到Zygote进程真正运行起来,并且进行相关初始化完成为止。 我们来详细分析下Zygote进程的启动过程...
  • Win32进程创建过程

    千次阅读 2020-04-09 22:30:15
    文章目录什么是进程进程内存空间的地址划分进程创建 什么是进程 运行在计算机上的程序,为当前的程序提供资源,举一个例子,进程相当于一个房子,房子里的东西由进程提供,房子里走动的人就是线程,进程仅仅提供...
  • 进程的创建,创建进程的两种方式

    万次阅读 2018-07-11 15:13:37
    一:进程创建 1,系统的初始化 2,一个进程在运行过程中开启了子进程 3,用户的交互式请求,而创建一个新进程(如双击qq) 4,一个批处理作业的初始化(只在大型机的批处理系统中应用) 关于进程创建,UNIX...
  • Linux中fork()函数创建进程

    千次阅读 2019-05-09 22:05:09
    Linux系统中学习fork函数创建进程前言一.准备工作二.任务三.感想 前言    最近学习到操作系统原理中的进程同步的知识点时,为了加深对进程的了解,就实践了一下在Linux系统中fork()函数的使用。 一.准备工作 ...
  • Dalvik虚拟机进程和线程的创建过程分析

    万次阅读 多人点赞 2013-06-03 01:03:25
    事实上,我们的确是可以在Java代码中创建进程和线程,也就是Dalvik虚拟机进程和线程。那么,这些Dalvik虚拟机所创建的进程和线程与其宿主Linux内核的进程和线程有什么关系呢?本文将通过Dalvik虚拟机进程和线程的...
  • CreateProcess 创建进程失败原因调查

    万次阅读 2015-11-05 14:54:44
    使用 CreateProcess 函数创建进程(调用外部程序)算是很常用的操作了,最近在工作中却遇到一个少见的怪现象,经常使用的一段代码(调用外部程序并等待其结束,主要就使用了 CreateProcess 函数),在少数某些机器上...
  • 循环中fork创建进程的个数

    千次阅读 2015-06-07 09:35:05
    linux下创建进程的系统调用是fork。其定义如下 #include #include pid_t fork(); 在循环中创建进程时,进程的个数是怎样的? 1、循环中没有任何父子进程的判断 #include #include #include #include int main...
  • Linux下创建进程的三种方式及特点

    万次阅读 多人点赞 2017-08-12 14:39:06
    在linux源码中这三个调用的执行过程是执行fork(),vfork(),clone()时,通过一个系统调用表映射到sys_fork(),sys_vfork(),sys_clone(),再在这三个函数中去调用do_fork()去做具体的创建进程工作。  fork   fork...
  • Linux下创建进程的三种方式

    千次阅读 2019-02-21 14:19:57
    在linux源码中这三个调用的执行过程是执行fork(),vfork(),clone()时,通过一个系统调用表映射到sys_fork(),sys_vfork(),sys_clone(),再在这三个函数中去调用do_fork()去做具体的创建进程工作。  fork   fork...
  • linux几种创建进程的方法

    千次阅读 2015-04-13 09:05:41
    在linux源码中这三个调用的执行过程是执行fork(),vfork(),clone()时,通过一个系统调用表映射到sys_fork(),sys_vfork(),sys_clone(),再在这三个函数中去调用do_fork()去做具体的创建进程工作。  fork   fork...
  • windows操作系统的进程创建过程

    千次阅读 2010-06-04 16:20:00
    进程
  • 进程创建过程(fork函数)

    千次阅读 2018-03-26 11:03:04
    创建过程: (1)给新进程分配一个标识符 (2)在内核中分配一个PCB,将其挂在PCB表上 (3)复制它的父进程的环境(PCB中大部分的内容) (4)为其分配资源(程序、数据、栈等) (5)复制父进程地址空间里的...
  • Linux创建进程的具体过程

    千次阅读 2015-04-09 11:40:45
    《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这篇文章来分析Linux操作系统创建一个子进程的具体流程。本文设计的Linux操作系统基于Linux-3.18.6内核,实验环境又实验楼提供,地址:...
  • 一、并发与并行 并行:多个计算机核心在同时处理多个任务,这时多个任务间是并行关系 并发:同时处理多个任务,但是内核在多个任务间不断地切换,达到好像都在处理...进程: 是一个动态过程的描述,占有计算机的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 702,355
精华内容 280,942
关键字:

创建进程的过程