精华内容
下载资源
问答
  • 一个应用程序有多少个进程

    千次阅读 2019-12-16 21:55:42
    一个程序几个进程在于这个程序的开发者的设置,可以是1个,也可以是多个的。 1.一个程序里有很多个进程 一个程序几个进程在于这个程序的开发者的设置,可以是1个,也可以是多个的。一个应用程序,启动多个处理进程...

    一个程序几个进程在于这个程序的开发者的设置,可以是1个,也可以是多个的。

    1.一个程序里有很多个进程

    一个程序几个进程在于这个程序的开发者的设置,可以是1个,也可以是多个的。一个应用程序,启动多个处理进程。换言之,所有进程隶属于当前应用程序;这是所谓的多进程服务。

    2.一个程序只有一个进程但被开启很多个

    启动多个同一应用程序,每个应用程序都是单进程。这个场景有些应用程序会禁用掉,有些是可以的,看应用程序的定位。如果允许,那么需要解决数据共享的问题(主要是数据写入);如果不允许,那么只能启动一个此类应用程序。

    对于现代操作系统(OS)以上两种场景时刻都在发生。比如QQ,允许同时登陆多个账号而出现多个qq程序。同时每个qq程序又有多个进程进行业务处理。

    展开全文
  • 一个进程只能一个线程池,现在还是这样吗? 一个线程池的最大线程数,是由哪些因素来决定的? 以前听说一个线程池最大是1000个线程,现在最多可以多少个线程?
  • 百度知道的答案: 比如显示图像的驱动程序,多个程序的显示都是需要他来执行。 我们玩游戏算一个程序,需要显示图像的驱动,声音驱动...然后你在执行一个命令行,顺序调用这两个程序,就会实现一个剪切文件的功能...
    百度知道的答案:
    比如显示图像的驱动程序,多个程序的显示都是需要他来执行。
    我们玩游戏算一个程序,需要显示图像的驱动,声音驱动、IO驱动的同时执行。
    就这么简单。

    我的理解:大家知道bat文件可以当做命令call的。
    你写了一个实现了拷贝的功能的bat文件,又写了一个实现删除功能的bat文件,这就是两个程序了。
    然后你在执行一个命令行,顺序调用这两个程序,就会实现一个剪切文件的功能。
    于是你剪切文件的这个一个进程就执行了你的这两个程序。

    其实这个东西咋一看不好理解,主要是人们总觉得程序应该是一个界面完整、包含业务逻辑和数据的软件。而在这句话中,一个函数就是一个程序了,程序片段也算程序。
    展开全文
  • 进程(process)和线程(thread)是操作系统的基本概念,但是...vs 线程 :一个进程可以包含多个线程" title="进程 vs 线程 :一个进程可以包含多个线程" style="border:0px; max-width:602px; height:auto; ma

    进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握。

    最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂。

    1.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。

    2.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。

    3.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

    4.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    一个车间里,可以有很多工人。他们协同完成一个任务。

    5.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    线程就好比车间里的工人。一个进程可以包括多个线程。

    6.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。

    7.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。

    8.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。

    9.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。

    10.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。

    不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。

    11.

    进程 <wbr>vs <wbr>线程 <wbr>:一个进程可以包含多个线程

    操作系统的设计,因此可以归结为三点:

    (1)以多进程形式,允许多个任务同时运行;

    (2)以多线程形式,允许单个任务分成不同的部分运行;

    (3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

    (完)

    展开全文
  • Android系统中的所有应用程序都是由所谓的Zygote进程(准确的说是/system/bin/app_process)“孵化”出来的。所有新创建的程序,都会继承Zygote进程内所有的资源。这样做的好处是免去了各个程序自己加载各自资源的...

    Android系统中的所有应用程序都是由所谓的Zygote进程(准确的说是/system/bin/app_process)“孵化”出来的。所有新创建的程序,都会继承Zygote进程内所有的资源。这样做的好处是免去了各个程序自己加载各自资源的时间,同时减少了系统总的内存使用量,代价仅仅是增加了每次系统重启的时间。

    但同时也带来了一些问题。例如,如果开发者想分析或调试某个应用程序,而某些分析工具必须要求由它自己来启动你的应用程序(例如Native程序内存检测工具valgrind), 就不能简单的通过直接调用app_process程序来完成。

    好在Google意识到了这个问题,在最近的Android系统代码中留下了这个口子,下面通过分析原代码来详述其实现原理(代码基于4.4.2_r2)。具体应用程序的启动过程就不分析了,这里重点分析和本文内容相关的部分。

    首先,来看ZygoteConnection类中的runOnce函数(代码位于frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java):

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        ...
        try {
            parsedArgs = new Arguments(args);
            ...
            applyInvokeWithSystemProperty(parsedArgs);
            ...
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName);
        }
        ....
        try {
            if (pid == 0) {
                ...
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                ...
            } else {
                ...
            }
        }
        ...
    }

    可以看到,其调用了一个叫做applyInvokeWithSystemProperty的函数,然后fork出了子进程。对于子进程来说,接下来调用了handleChileProc函数。先来看第一个函数(代码位于frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java):

    public static void applyInvokeWithSystemProperty(Arguments args) {
        if (args.invokeWith == null && args.niceName != null) {
            if (args.niceName != null) {
                String property = "wrap." + args.niceName;
                if (property.length() > 31) {
                    property = property.substring(0, 31);
                }
                args.invokeWith = SystemProperties.get(property);
                if (args.invokeWith != null && args.invokeWith.length() == 0) {
                    args.invokeWith = null;
                }
            }
        }
    }

    其中所谓的niceName就是要启动程序的包名。代码很简单,如果包名不为空的话,就查看一下系统中有没有属性名是在你的包名前加上“wrap.”的属性。如果有的话,那么就将参数列表中的invokeWith变量的值设置成那个系统属性;如果没有的话,就将其设置成空。

    通常,这个属性会被设置成你要使用的分析程序的名字。同时,由于属性名包含你要跑的程序的包名,所以只对你关心的程序起作用。

    注意,这里还有个限制条件,就是拼完之后的属性名不能超过31个字符,如果超过的话只会取前31个字符。因此,这里就有了一个隐性的限制条件,就是你程序的包名不能太长(不要超过26个字符)。

    接下来,当子进程启动之后,会继续调用handleChileProc函数,做接下来的工作(代码位于frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java):

    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        ...
        if (parsedArgs.runtimeInit) {
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        pipeFd, parsedArgs.remainingArgs);
            } else {
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs);
            }
        } else {
        ...
        }
    }

    这里会根据刚才在handleChileProc函数中对参数列表中的invokeWith变量设置值的不同做不一样的处理。如果invokeWith是空的话,这也是通常的情况,就直接调用RuntimeInit.zygoteInit函数了;如果不为空的话,也就是本文要分析的情况,会调用WrapperInit.execApplication函数(代码位于frameworks\base\core\java\com\android\internal\os\WrapperInit.java):

    public static void execApplication(String invokeWith, String niceName,
                int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
        StringBuilder command = new StringBuilder(invokeWith);
        command.append(" /system/bin/app_process /system/bin --application");
        if (niceName != null) {
            command.append(" '--nice-name=").append(niceName).append("'");
        }
        command.append(" com.android.internal.os.WrapperInit ");
        command.append(pipeFd != null ? pipeFd.getInt$() : 0);
        command.append(' ');
        command.append(targetSdkVersion);
        Zygote.appendQuotedShellArgs(command, args);
        Zygote.execShell(command.toString());
    }

    函数的功能很简单,就是拼一个命令行字符串,然后交给Zygote.execShell函数去执行(代码位于libcore\dalvik\src\main\java\dalvik\system\Zygote.java):

    public static void execShell(String command) {
        String[] args = { "/system/bin/sh", "-c", command };
        try {
            Libcore.os.execv(args[0], args);
        } catch (ErrnoException e) {
            throw new RuntimeException(e);
        }
    }

    这个函数实际上最后会调用系统的execv函数,用shell程序(/system/bin/sh)来执行指定的命令。而这个要执行的命令是在WrapperInit.execApplication函数中拼出来的。

    分析前面的代码,可以知道,命令格式大致如下:

    <属性值> /system/bin/app_process /system/bin --application '--nice-name=<包名>' com.android.internal.os.WrapperInit <管道号> <目标SDK版本号> <其它剩下的参数>

    这里的属性值通常被设置成你要使用的那个测试工具,或者是一个特定的测试脚本。所以,推论这样下去的结果就是让你使用的测试工具启动app_process进程,并给其传递相应的参数,从而让它接着启动你要测试的程序。

    这里特别说明一下,参数中的“--nice-name”被设置成你程序的包名,但它的作用只是将子进程的名字改成你的包名,并不是指定要app_process启动你的程序。另外,在所谓的“其它剩下的参数中”,会指定一个类名,但它也不是你所要启动程序的类名,无论你要启动的程序是什么,这个类名都被指定成“android.app.ActivityThread”。而真正决定到底启动哪个Java程序的另有玄机。

    那到底是不是这样呢?我们接着看app_process中的main函数实现(代码位于frameworks\base\cmds\app_process\app_main.cpp):

    int main(int argc, char* const argv[])
    {
        ...
        AppRuntime runtime;
        const char* argv0 = argv[0];
    
        argc--;
        argv++;
    
        int i = runtime.addVmArguments(argc, argv);
    
        bool zygote = false;
        bool startSystemServer = false;
        bool application = false;
        const char* parentDir = NULL;
        const char* niceName = NULL;
        const char* className = NULL;
        while (i < argc) {
            const char* arg = argv[i++];
            if (!parentDir) {
                parentDir = arg;
            } else if (strcmp(arg, "--zygote") == 0) {
                zygote = true;
                niceName = "zygote";
            } else if (strcmp(arg, "--start-system-server") == 0) {
                startSystemServer = true;
            } else if (strcmp(arg, "--application") == 0) {
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {
                niceName = arg + 12;
            } else {
                className = arg;
                break;
            }
        }
    
        if (niceName && *niceName) {
            setArgv0(argv0, niceName);
            set_process_name(niceName);
        }
    
        runtime.mParentDir = parentDir;
    
        if (zygote) {
            ...
        } else if (className) {
            runtime.mClassName = className;
            runtime.mArgC = argc - i;
            runtime.mArgV = argv + i;
            runtime.start("com.android.internal.os.RuntimeInit",
                    application ? "application" : "tool");
        } else {
            ...
        }
    }
    对照前面拼的命令,可以看出,传递给app_process的参数的含义如下:

    1)“/system/bin”是所谓的父路劲(Parent Directory);

    2)“--application”表示让app_process启动一个应用程序;

    3)“--nice-name=<包名>”指定要实际启动的那个程序的包名;

    4)“com.android.internal.os.WrapperInit”字面上是指定一个类名,app_process不能直接启动一个运行Dalvik指令的程序,必须要借助一些Java层的程序,下面分析中会提到。

    由于命令没有指定--zygote,并且设置了类名是“com.android.internal.os.WrapperInit”,所以接下来会调用AppRuntime.start函数,第一个参数是“com.android.internal.os.RuntimeInit”,第二个参数是“application”,并且将AppRuntime实例的mClassName设置成了“com.android.internal.os.WrapperInit”。

    由于AppRuntime类继承自AndroidRuntime类,且没有重载其中的start函数,所以这里实际是调用的AndroidRuntime.start函数(代码位于frameworks\base\core\jni\AndroidRuntime.cpp):

    void AndroidRuntime::start(const char* className, const char* options)
    {
        ...
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env) != 0) {
            return;
        }
        onVmCreated(env);
    
        if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
    
        jclass stringClass;
        jobjectArray strArray;
        jstring classNameStr;
        jstring optionsStr;
    
        stringClass = env->FindClass("java/lang/String");
        assert(stringClass != NULL);
        strArray = env->NewObjectArray(2, stringClass, NULL);
        assert(strArray != NULL);
        classNameStr = env->NewStringUTF(className);
        assert(classNameStr != NULL);
        env->SetObjectArrayElement(strArray, 0, classNameStr);
        optionsStr = env->NewStringUTF(options);
        env->SetObjectArrayElement(strArray, 1, optionsStr);
    
        char* slashClassName = toSlashClassName(className);
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
           ...
        } else {
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
            if (startMeth == NULL) {
                ALOGE("JavaVM unable to find main() in '%s'\n", className);
            } else {
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
            }
        }
        ...
    }

    代码很简单,启动并初始化好Dalvik虚拟机,然后找出名字为className参数指定的类(这里是“com.android.internal.os.RuntimeInit”),并调用它的静态main方法,且将传递进来的className和options参数转换成字符串数组传递进去。所以,接下来我们看RuntimeInit.main函数(代码位于frameworks\base\core\java\com\android\internal\os\RuntimeInit.java):

    public static final void main(String[] argv) {
        ...
        commonInit();
    
        nativeFinishInit();
        ...
    }

    还是继续做一些初始化的动作,那传进来的“com.android.internal.os.WrapperInit”用到了什么地方,具体的程序又是怎么被启动的呢?

    奥秘在nativeFinishInit函数中,这是一个Native的函数(代码位于frameworks\base\core\jni\AndroidRuntime.cpp):

    static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
    {
        gCurRuntime->onStarted();
    }

    这个函数会调用当前AndroidRuntime.onStarted函数,而通过前面可以看到,实际创建的是AppRuntime类的实例,且onStarted函数被申明成虚函数,所以由于多态性,实际调用的是AppRuntime.onStarted函数(代码位于frameworks\base\cmds\app_process\app_main.cpp):

    virtual void onStarted()
    {
        ...
        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgC, mArgV);
        ...
    }

    看到了吗,它会接着调用mClassName变量指定类中的main函数,并且传递参数。但是,这个参数已经不是前面那个完整的命令了,而是截取了在类名(本例中是““com.android.internal.os.WrapperInit”)后面剩下命令字符串作为参数。

    那好,我们接着看WrapperInit.main函数的实现(代码位于frameworks\base\core\java\com\android\internal\os\WrapperInit.java):

    public static void main(String[] args) {
        try {
            int fdNum = Integer.parseInt(args[0], 10);
            int targetSdkVersion = Integer.parseInt(args[1], 10);
            ...
    
            ZygoteInit.preload();
    
            String[] runtimeArgs = new String[args.length - 2];
            System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
            RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
        } catch (ZygoteInit.MethodAndArgsCaller caller) {
            caller.run();
        }
    }

    很简单,在命令字符串中接着解析出管道号和目标SDK版本号,然后调用RuntimeInit.wrapperInit,并将SDK版本号和后面剩下的命令传递进去。

    注意,这里还特别调用了ZygoteInit.preload函数,这是因为当前的子进程已经是一个全新的app_process进程了(通过exec执行的),并没有继承Zygote进程的所有资源,所以要重新加载一下。

    接着看RuntimeInit.wrapperInit(代码位于frameworks\base\core\java\com\android\internal\os\RuntimeInit.java):

    public static void wrapperInit(int targetSdkVersion, String[] argv)
                throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
    
        applicationInit(targetSdkVersion, argv);
    }
    
    private static void applicationInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        ...
        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            ...
        }
    
        invokeStaticMain(args.startClass, args.startArgs);
    }

    RuntimeInit.wrapperInit函数很简单,简单的直接调用RuntimeInit.applicationInit函数。

    而RuntimeInit.applicationInit函数接着解析剩下的参数,从中解析出要加载并运行的类和参数。前面曾经提到过,这个类,无论你启动什么程序,都是“android.app.ActivityThread”。所以,下面就会加载“android.app.ActivityThread”类,执行它的main函数,并将剩下的参数传递进去。

    讲到这里,估计大家还在疑惑,还有一个大问题没有解决,所有程序都加载同样的类,那我们自己的程序到底是在哪里加载进来的呢?

    这个问题说来话长,限于本篇的篇幅,不能做太详细的介绍,只能大致说一下。由于Android系统的特殊性,要启动一个正常的应用程序,需要涉及到一个ActivityManagerService系统服务,还有一个就是Zygote进程,大概经历了以下几步:

    1)ActivityManagerService收到一个Binder事件,让它启动一个指定的Activity。通常,当你在Launcher中点击一个应用程序图标之后,是由Launcher负责将这个事件发送给ActivityManagerService的。

    当然,你也可以通过am命令,向ActivityManagerService发送任何你想要的事件,例如:

    adb shell am start -n <包名>/.<Activity名>

    2)ActivityManagerService查找本地记录,发现并没有任何已运行的程序包含这个Activity,因此通过本地套接字(Local Socket)向Zygote进程发消息,请求它帮忙启动一个新的进程。

    这个请求是同步的,当一个新的子进程被创建出来后,ActivityManagerService会得到这个子进程的进程号,并将这个进程号和随后要在这个进程中启动程序的信息一一对应的记录下来,等待以后查询时用。

    而对于那个子进程来说,它启动起来之后,都会去执行“android.app.ActivityThread”类中的main函数。上面分析的部分,只是说明了从Zygote进程拿到启动新进程的本地套接字消息(ZygoteConnection.runOnce函数),到创建一个新的进程并执行“android.app.ActivityThread”类的main函数(RuntimeInit.wrapperInit)之间,为了达到让你的工具启动程序的目的,所做的一些特殊的处理。

    3)子进程在“android.app.ActivityThread”类的“领导”下,接着会试着附着(Attach)到那个应用程序上,这也是这个子进程被创建出来的真正目的。

    这里所谓的附着,其实就是子进程通过Binder通信,请求ActivityManagerService告知,对应自己这个子进程号的应用程序的信息(包括包名、组件名等)。在前一步中已经说明了,进程号和应用程序信息是一一对应的记录在ActivityManagerService中的。

    当子进程得到了应用程序信息之后,就会用类加载器将其加载进来,并执行。

    通过以上的分析,回答了我一直以来都有的一个疑问,那就是为什么不能直接通过app_process启动一个应用程序,非要绕这么个大圈子呢?答案其实很简单,你如果直接在命令行中敲入app_process命令,即使你把命令都敲对了也没用,因为你绕过了ActivityManagerService,它那并没有注册你这个进程号对应的要启动的程序的信息。而通过前面的代码分析,如果你对应用程序设置了wrapper系统属性的话,ActivityManagerService并没有被绕过,它那确实记录着你子进程号对应的应用程序信息,后面还是能够查找的到,一切的一切只是让你启动的那个子进程自己去切换环境,执行你设定的工具程序,再让它继续启动你程序。

    展开全文
  • 一个进程最多能包含多少线程

    万次阅读 2012-10-20 16:22:34
    实验蛮简单的,但是,我不由想到了,一个进程最多能包含多少个线程。 在网上查了查,貌似也没找到多少这方面的资料。大部分都是关于服务器多线程链接sever的,关于本机可执行exe的进程数倒是没有什么涉及。 我觉得...
  • 程序 进程 线程

    千次阅读 2007-06-04 08:55:00
    一,什么是进程? CPU在一个瞬间只能运行一道程序。但是在一个时间段内可能会运行多道程序,这样就给了我们一种程序并行的概念。这就是“伪并行”:CPU在多...一个进程就是一个正在执行的程序包括程序计数器、寄存器
  • 时间片即CPU分配给各个程序的时间,每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。...
  • 程序进程与线程(

    千次阅读 多人点赞 2018-10-19 09:33:53
    程序进程具体的场景,某天你爸妈不在家,你必须要自己做饭、洗衣服等等。你要做饭首先你得有做饭手册呀,这手册中包含了做饭所需的各种步骤(比如洗米,把米放到电饭煲中,插上电饭煲电源等等),当...
  • 程序进程 程序:是指编译好的二进制文件,存放在磁盘上,...那么我们可以形象的将程序比作一个剧本,这个剧本就是一张一张的纸组成的,那么就是进程就要演的戏,一出戏上面包括舞台、演员、灯光、道具等等。同一...
  • 程序进程,线程的区别和联系

    万次阅读 多人点赞 2018-08-26 22:27:18
    进程程序区别和联系表现在以下方面: 1)程序只是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体。而进程则不同,它是程序在...2)进程程序并不是一一对应的,一个程序执行在不同的数据集上...
  • 允许其中的串行程序运行在一个或多个可共享的cpu上,同时也允许每个串行程序都运行在专为他服务的cpu上。 并行程序: 可以在并行的硬件上执行的并发程序。 并发程序代表了所有可以实现并发行为的程序包含了并行...
  • 操作系统面试之——程序进程、线程 题注:《面试宝典》操作系统部分错误、漏洞较多,笔者对此参考相关书籍和自己观点进行了重写,供大家参考。 程序进程、线程 1.程序进程. 进程由两部分组成:1)...
  • 进程是指一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统运行程序的基本单位,因此进程是动态的。 线程与进程相似,但线程是一个进程更小的执行单位。一个进程在其执行的过程中可以产生多个...
  • fenny@163.net,这是我在互联网上申请的第一个email地址,那还是在1996年的时候,在学校的开放实验室里。记得Forest还拿这个名字打趣过我,说你怎么起了这么个名字,好歹也得叫个dollar什么的呀
  • 程序(program)只能一个进程一个进程就是一个程序。有人说,我打开一个程序,比如chrome,有十多个进程呢,这是咋回事。那就是十多个程序,操作系统给他们分配了彼此独立的内存,相互执行不受彼此约束,分配同样...
  • 多个进程监听同一个端口(multiple processes listen on same port) 方式1:通过 fork 创建子进程的方式可以实现,其他情况下不行。 当连接到来时,子进程、父进程都可以 accept, 这就是著名的“惊群”问题...
  • (1)一个进程一个正在执行程序的实例,包括程序计数器,变量的当前值和寄存器以及 程序,输入输出,状态。程 序是存储在磁盘上的一系列代码和数据。 (2)进程是一次运行的活动,属于一种动态概念,程序是一组...
  • 程序进程、线程的联系与区别

    千次阅读 2014-09-26 22:38:38
    程序:一组指令的有效集合 进程程序的执行就是进程。也可以把进程看成一个独立的程序,在内存中有...换句话说,就是一个进程可以包含多个线程,并且至少有一个主线程,同时同一进程的线程共享该进程的代码和数据
  • 一个正在执行的程序的实例 担当分配系统资源的实体(cpu时间,内存) 进程信息被放在一进程控制块的数据结构中,这个进程控制块称为PCB,进程控制块的数据结构叫task_struct  这个task_struct 包括以下几个...
  •         进程程序之间可以形成一对一,一对多,多对一,多对多的关系,分别举例说明在什么情况下会形成这样的关系?...(3)进程是具有独立功能的程序一个...
  • 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. . 线程是指进程内的一个执行单元,也是进程内的可调度实体. 线程是CPU调度和分派的基本单位,它是比...
  • 一个进程可以创建多少线程

    千次阅读 2018-07-18 23:10:23
    理论上,一个进程可用虚拟空间是2G,默认情况下,线程的栈的大小是1MB,所以理论上最多只能创建2048个线程。如果要创建多于2048的话,必须修改编译器的设置。 #include&lt;windows.h&gt; #include&lt;...
  • 程序只能加载

    千次阅读 2012-02-15 21:58:20
    此方法提出者的观点是这样的:当程序运行时,在某个文件临时文件中写一个标记1;在程序退出时把这个标记改成0。在程序加载时,检查这个文件中的标记值 是什么,如果是0,则意味这系统中没有程序的运行实例。此时可以...
  • 程序进程和线程的区别与联系

    千次阅读 2018-05-18 03:01:21
    借鉴了各大网站,总结出的个人... 程序(这里和前边指的是包含了线程,进程程序的抽象概念)有顺序执行(顺序性,只有前操作结束后才能执行后续操作;封闭性,程序一旦运行,其执行结果不受外界因素的影响;可...
  • 进程

    千次阅读 2021-04-10 21:41:24
    1.进程的概念 程序: (1)存放在磁盘上的指令和数据的有序集合(文件) ...一个程序执行的时候会创建多个进程 通过系统数据段,可以使得操作系统有效的管理进程,系统数据段中主要包含进程控制块
  • linux(十四)程序进程的深入研究

    千次阅读 2021-05-12 09:51:25
    每个程序可以创建一个或者多个进程 僵尸进程:占用资源,却无法正常运行工作的进程 孤儿进程:无父进程 进程状态: 1.可运行状态 2.sleep状态 可中断sleep状态 不可中断sleep状态 3.僵死状...
  • 进程——通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动。 组成部分:操作系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程统计信息的地方 地址空间。它包含...
  • 一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以作为一个进程来实现,也可以作为一个线程(或作为一个中断任务)来实现...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 405,687
精华内容 162,274
关键字:

一个程序只能包含一个进程