• UNIX基础知识之程序和进程


    一、程序

      程序(program)是存放在磁盘上、处于某个目录中的一个可执行文件。使用6个exec函数中的一个由内核将程序读入存储器,并使其执行。

    二、进程和进程ID

      程序的执行实例被称为进程(process)。某些操作系统使用任务(task)表示正在执行的程序。

      UNIX系统确保每个进程都有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一个非负整数。

      程序清单1-4 打印进程ID

    [root@localhost unix_env_advance_prog]# cat prog1-4.c
    #include "apue.h"
    
    int
    main(void)
    {
            printf("hello world from process ID %d
    ", getpid());
            exit(0);
    }

      编译后运行:

    [root@localhost unix_env_advance_prog]# ./prog1-4
    hello world from process ID 23987
    [root@localhost unix_env_advance_prog]# ./prog1-4
    hello world from process ID 23988

      此程序运行时,它调用函数getpid得到其进程ID。

    三、进程控制

      有三个用于进程控制的主要函数:fork、exec和waitpid。(exec有六种变体,但经常把它们统称为exec函数。)

      程序清单1-5 从标准输入读入命令并执行(类shell程序的简化实现):

    [root@localhost unix_env_advance_prog]# cat prog1-5.c
    #include "apue.h"
    #include <sys/wait.h>
    
    int
    main(void)
    {
            char    buf[MAXLINE];   /* from apue.h */
            pid_t   pid;
            int     status;
    
            printf("%% "); /* print prompt (printf requires %% to print %) */
            while(fgets(buf, MAXLINE, stdin) != NULL)
            {
                    if(buf[strlen(buf) - 1] == '
    ')
                            buf[strlen(buf) - 1] = 0; /* replace newline with null */
    
                    if((pid = fork()) < 0)
                    {
                            err_sys("fork error");
                    }
                    else if(pid == 0)  /* child */
                    {
                            execlp(buf, buf, (char *)0);
                            err_ret("couldn't execute: %s", buf);
                            exit(127);
                    }
    
                    /* parent */
                    if((pid = waitpid(pid, &status, 0)) < 0)
                            err_sys("waitpid error");
                    printf("%% ");
            }
            exit(0);
    }

      编译后运行:

    [root@localhost unix_env_advance_prog]# ./prog1-5
    % ls
    apue.h   Makefile  prog1-1.c  prog1-2.c  prog1-3.c  prog1-4.c  prog1-5.c
    error.c  prog1-1   prog1-2    prog1-3    prog1-4    prog1-5
    %

      用标准I/O函数fgets从标准输入一次读一行,当键入文件结束符(通常是Ctrl+D)作为行的第1个字符时,fgets返回一个null指针,于是终止循环,进程也就终止。

      因为fgets返回的每一行都以换行符终止,后随一个null字节,故用标准C函数strlen计算此字符串的长度,然后用一个null字节替换换行符。这样做是因为execlp函数要求参数以null而不是以换行符结束。

      调用fork创建一个新进程。新进程是调用进程的复制品,我们称调用进程为父进程,新创建的进程为子进程。fork向父进程返回新子进程的进程ID(非负),对子进程则返回0。因为fork创建一个新进程,所以说它被调用一次(由父进程),但返回两次(分别在父进程及子进程中)。

      在子进程中,调用execlp以执行从标准输入读入的命令。这就用新的程序文件替换了子进程原先执行的程序文件。fork和跟随其后的exec两者的组合是某些操作系统所称道产生(spawn)一个新进程。在UNIX系统中,这两个部分相互分隔,构成两个函数。

      子进程调用execlp执行新程序文件,而父进程希望等待子进程终止,这一要求由调用waitpid实现,其参数指定要等待的进程(在这里,pid参数是子进程ID)。waitpid函数返回子进程的终止状态(status变量)。如果需要,可以使用status变量的值准确地判定子进程是因何终止的。

      小知识:^D表示一个控制字符。控制字符是特殊字符,其形成方法是:在键盘上按下控制键——通常被标记为Control或Ctrl,同时按另一个键。Control-D或^D是默认的文件结束符。

    四、线程和线程ID

      通常,一个进程只有一个控制线程(thread),同一时刻只执行一组机器指令。对于某些问题,如果不同部分各使用一个控制线程,那么整个问题解决起来就容易很多。另外,多个控制线程也能充分利用多处理器系统的并行性。

      在一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。

      与进程相同,线程也用ID标识。但是,线程ID只在它所属进程内起作用。一个进程中的线程ID在另一个进程中并无意义。当在一个进程中对多个线程进行操作时,我们用线程ID引用相应的线程。

      控制线程的函数与控制进程的函数类似,但另有一套。在进程模型建立很久之后,线程模型才被引入到UNIX系统中,这两个模型之间存在复杂的相互作用。

    本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

  • 相关阅读:
    arduino远程刷新(烧录)固件
    通过语音控制电灯、空调、房门。芝麻开门
    arduino红外遥控库IRremote的IRsend类sendRaw函数溢出问题及其解决方法
    64位sql server 如何使用链接服务器连接Access
    Linux常用命令汇总
    常用的排序算法总结
    MongoDB数据库常用SQL命令 — MongoDB可视化工具Robo 3T
    SynchronousQueue队列程序的执行结果分析
    输入编码,自动匹配并输出相对应的名称
    linux五种IO模型与事件驱动模型
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3495129.html
Copyright © 2020-2023  润新知