精华内容
下载资源
问答
  • golang 进程属性和控制
    千次阅读
    2017-10-23 09:07:37

    golang 进程属性和控制

    每个进程都有一些属性,os 包提供了一些函数可以获取进程属性。

    1.1. 进程 ID

    每个进程都会有一个进程ID,可以通过 os.Getpid 获得。同时,每个进程都有创建自己的父进程,通过 os.Getppid 获得。

    1.2. 进程凭证

    Unix 中进程都有一套数字表示的用户 ID(UID) 和组 ID(GID),有时也将这些 ID 称之为进程凭证。Windows 下总是 -1。

    1.2.1. 实际用户 ID 和实际组 ID

    实际用户 ID(real user ID)和实际组 ID(real group ID)确定了进程所属的用户和组。登录 shell 从 /etc/passwd 文件读取用户 ID 和组 ID。当创建新进程时(如 shell 执行程序),将从其父进程中继承这些 ID。

    可通过 os.Getuid()os.Getgid() 获取当前进程的实际用户 ID 和实际组 ID;

    1.2.2. 有效用户 ID 和有效组 ID

    大多数 Unix 实现中,当进程尝试执行各种操作(即系统调用)时,将结合有效用户 ID、有效组 ID,连同辅助组 ID 一起来确定授予进程的权限。内核还会使用有效用户 ID 来决定一个进程是否能向另一个进程发送信号。

    有效用户 ID 为 0(root 的用户 ID)的进程拥有超级用户的所有权限。这样的进程又称为特权级进程(privileged process)。某些系统调用只能由特权级进程执行。

    可通过 os.Geteuid() 和 os.Getegid() 获取当前进程的有效用户 ID(effective user ID)和有效组 ID(effectvie group ID)。

    通常,有效用户 ID 及组 ID 与其相应的实际 ID 相等,但有两种方法能够致使二者不同。一是使用相关系统调用;二是执行 set-user-ID 和 set-group-ID 程序。

    1.2.3. Set-User-ID 和 Set-Group-ID 程序

    set-user-ID 程序会将进程的有效用户 ID 置为可执行文件的用户ID(属主),从而获得常规情况下并不具有的权限。set-group-ID 程序对进程有效组 ID 实现类似任务。(有时也将这程序简称为 set-UID 程序和 set-GID 程序。)

    与其他文件一样,可执行文件的用户 ID 和组 ID 决定了该文件的所有权。在 6.1 os — 平台无关的操作系统功能实现 中提到过,文件还拥有两个特别的权限位 set-user-ID 位和 set-group-ID 位,可以使用 os.Chmod 修改这些权限位(非特权用户进程只能修改其自身文件,而特权用户进程能修改任何文件)。

    文件设置了 set-user-ID 位后,ls -l 显示文件后,会在属主用户执行权限字段上看到字母 s(有执行权限时) 或 S(无执行权限时);相应的 set-group-ID 则是在组用户执行位上看到 s 或 S。

    当运行 set-user-ID 程序时,内核会将进程的有效用户 ID 设置为可执行文件的用户 ID。set-group-ID 程序对进程有效组 ID 的操作与之类似。通过这种方法修改进程的有效用户 ID 或组 ID,能够使进程(换言之,执行该程序的用户)获得常规情况下所不具有的权限。例如,如果一个可执行文件的属主为 root,且为此程序设置了 set-user-ID 权限位,那么当运行该程序时,进程会取得超级用户权限。

    也可以利用程序的 set-user-ID 和 set-group-ID 机制,将进程的有效 ID 修改为 root 之外的其他用户。例如,为提供一个受保护文件的访问,可采用如下方案:创建一个具有对该文件访问权限的专有用户(组)ID,然后再创建一个 set-user-ID(set-group-ID)程序,将进程有效用户(组)ID 变更为这个专用 ID。这样,无需拥有超级用户的所有权限,程序就能访问该文件。

    Linux 系统中经常使用的 set-user-ID 程序,如 passwd。

    测试 set-user-ID 程序

    在 Linux 的某个目录下,用 root 账号创建一个文件:

    echo "This is my shadow, studygolang." > my_shadow.txt

    然后将所有权限都去掉:chmod 0 my_shadow.txt。 ls -l 结果类似如下:

    ---------- 1 root root 32 6月 24 17:31 my_shadow.txt

    这时,如果非 root 用户是无法查看文件内容的。

    接着,用 root 账号创建一个 main.go 文件,内容如下:

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "log"
        "os"
    )
    
    func main() {
        file, err := os.Open("my_shadow.txt")
        if err != nil {
            log.Fatal(err)
        }
        defer file.Close()
    
        data, err := ioutil.ReadAll(file)
        if err != nil {
            log.Fatal(err)
        }
    
        fmt.Printf("my_shadow:%s\n", data)
    }

    就是简单地读取 my_shadow 文件内容。go build main.go 后,生成的 main 可执行文件,权限是:-rwxrwxr-x。

    这时,切换到非 root 用户,执行 ./main,会输出:

    open my_shadow.txt: permission denied

    因为这时的 main 程序生成的进程有效用户 ID 是当前用户的(非 root)。

    接着,给 main 设置 set-user-ID 位:chmod u+s main,权限变为 -rwsrwxr-x,非 root 下再次执行 ./main,输出:

    my_shadow:This is my shadow, studygolang.

    因为设置了 set-user-ID 位,这时 main 程序生成的进程有效用户是 main 文件的属主,即 root 的 ID,因此有权限读 my_shadow.txt。

    1.2.4. 修改进程的凭证

    os 包没有提供相应的功能修改进程的凭证,在 syscall 包对这些系统调用进行了封装。因为 https://golang.org/s/go1.4-syscall,用户程序不建议直接使用该包,应该使用 golang.org/x/sys 包代替。

    该包提供了修改进程各种 ID 的系统调用封装,这里不一一介绍。

    此外,os 还提供了获取辅助组 ID 的函数:os.Getgroups()。

    1.2.5. 操作系统用户

    包 os/user 允许通过名称或 ID 查询用户账号。用户结构定义如下:

    type User struct {
        Uid      string // user id
        Gid      string // primary group id
        Username string
        Name     string
        HomeDir  string
    }

    User 代表一个用户帐户。

    OSIX 系统中 Uid 和 Gid 字段分别包含代表 uid 和 gid 的十进制数字。在 Windows 系统中 Uid 和 Gid 包含字符串格式的安全标识符(SID)。在 Plan 9 系统中,Uid、Gid、Username 和 Name 字段是 /dev/user 的内容。

    Current 函数可以获取当前用户账号。而 Lookup 和 LookupId 则分别根据用户名和用户 ID 查询用户。如果对应的用户不存在,则返回 user.UnknownUserErroruser.UnknownUserIdError

    package main
    
    import (
        "fmt"
        "os/user"
    )
    
    func main() {
        fmt.Println(user.Current())
        fmt.Println(user.Lookup("xuxinhua"))
        fmt.Println(user.LookupId("0"))
    }
    
    // Output:
    // &{502 502 xuxinhua  /home/xuxinhua} <nil>
    // &{502 502 xuxinhua  /home/xuxinhua} <nil>
    // &{0 0 root root /root} <nil>

    1.3. 进程的当前工作目录

    一个进程的当前工作目录(current working directory)定义了该进程解析相对路径名的起点。新进程的当前工作目录继承自其父进程。

    func Getwd() (dir string, err error)

    Getwd 返回一个对应当前工作目录的根路径。如果当前目录可以经过多条路径抵达(比如符号链接),Getwd 会返回其中一个。对应系统调用:getcwd

    func Chdir(dir string) error

    相应的,Chdir 将当前工作目录修改为 dir 指定的目录。如果出错,会返回 *PathError 类型的错误。对应系统调用 chdir

    另外,os.File 有一个方法:Chdir,对应系统调用 fchidr(以文件描述符为参数),也可以改变当前工作目录。

    1.4. 改变进程的根目录

    每个进程都有一个根目录,该目录是解释绝对路径(即那些以/开始的目录)时的起点。默认情况下,这是文件系统的真是根目录。新进程从其父进程处继承根目录。有时可能需要改变一个进程的根目录(比如 ftp 服务就是一个典型的例子)。系统调用 chroot 能改变一个进程的根目录,Go 中对应的封装在 syscall.Chroot

    除此之外,在 fork 子进程时,可以通过给 syscall.SysProcAttr 结构的 Chroot 字段指定一个路径,来初始化子进程的根目录。

    1.5. 进程环境列表

    每个进程都有与其相关的称之为环境列表(environment list)的字符串数组,或简称环境(environment)。其中每个字符串都以 名称=值(name=value)形式定义。因此,环境是“名称-值”的成对集合,可存储任何信息。常将列表中的名称称为环境变量(environment variables)。

    新进程在创建之时,会继承其父进程的环境副本。这是一种原始的进程间通信方式,却颇为常用。环境(environment)提供了将信息和父进程传递给子进程的方法。创建后,父子进程的环境相互独立,互不影响。

    环境变量的常见用途之一是在 shell 中,通过在自身环境中放置变量值,shell 就可确保把这些值传递给其所创建的进程,并以此来执行用户命令。

    在程序中,可以通过 os.Environ 获取环境列表:

    func Environ() []string

    返回的 []string 中每个元素是 key=value 的形式。

    func Getenv(key string) string

    Getenv 检索并返回名为 key 的环境变量的值。如果不存在该环境变量会返回空字符串。有时候,可能环境变量存在,只是值刚好是空。为了区分这种情况,提供了另外一个函数 LookupEnv()

    func LookupEnv(key string) (string, bool)

    如果变量名存在,第二个参数返回 true,否则返回 false。

    func Setenv(key, value string) error

    Setenv 设置名为 key 的环境变量,值为 value。如果出错会返回该错误。(如果值之前存在,会覆盖)

    func Unsetenv(key string) error

    Unsetenv 删除名为 key 的环境变量。

    func Clearenv()

    Clearenv 删除所有环境变量。

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        fmt.Println("The num of environ:", len(os.Environ()))
        godebug, ok := os.LookupEnv("GODEBUG")
        if ok {
            fmt.Println("GODEBUG==", godebug)
        } else {
            fmt.Println("GODEBUG not exists!")
            os.Setenv("GODEBUG", "gctrace=1")
            fmt.Println("after setenv:", os.Getenv("GODEBUG"))
        }
    
        os.Clearenv()
        fmt.Println("clearenv, the num:", len(os.Environ()))
    }
    
    // Output:
    // The num of environ: 25
    // GODEBUG not exists!
    // after setenv: gctrace=1
    // clearenv, the num: 0

    另外,ExpandEnvGetenv 功能类似,不过,前者使用变量方式,如:

    os.ExpandEnv("$GODEBUG")os.Getenv("GODEBUG") 是一样的。

    实际上,os.ExpandEnv 调用的是 os.Expand(s, os.Getenv)

    func Expand(s string, mapping func(string) string) string

    Expand 能够将 ${var}$var 形式的变量,经过 mapping 处理,得到结果。


    参考
    http://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter10/10.2.html

    更多相关内容
  • 05_父子进程_文件描述

    千次阅读 2020-07-21 17:59:41
    目录1. 进程概述1.1 程序和进程1.2 并行和并发并行和... 进程控制5.1 结束进程5.2 孤儿进程5.3 僵尸进程5.3 进程回收 wait waitpid6. dup,dup2,fcntl函数6.1 dup和dup26.2 fcntl函数 代码: https://github.com/WHa

    代码: https://github.com/WHaoL/study/tree/master/00_06_Linux_SystemCode_and_SocketCode

    代码: https://gitee.com/liangwenhao/study/tree/master/00_06_Linux_SystemCode_and_SocketCode

    1. 进程概述

    1.1 程序和进程

    程序:磁盘文件, 只占用磁盘资源
    进程:一个启动之后的程序
        进程不占用磁盘资源,占用cpu和内存资源
        
    进程,是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竟争计算机系统资源的基本单位。每一个进程都有一个自己的地址空间,即进程空间或(虚空间)。进程空间的大小 只与处理机的位数有关,一个 16 位长处理机的进程空间大小为 2^16^ ,而 32 位处理机的进程空间大小为 2^32^ 。    
    

    1.2 并行和并发

    并行和并发

    1.并发

    2.并行
    在这里插入图片描述

    并发: 在一个比较短的时间段之内处理的任务的量

    CPU时间片

    时间片即CPU分配给各个程序的时间,每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费。

    • 在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。

    • 但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,为了公平处理,方法就是引入时间片,让每个程序轮流执行。

    在Linux的内核处理过程中,每一个进程默认会有一个固定的时间片来执行命令(默认为1/100秒),这段时间内进程被分配到CPU,然后独占使用。如果使用完,同时未到时间片的规定时间,那么就主动放弃CPU的占用,如果到时间片尚未完成工作,那么CPU的使用权也会被收回,进程将会被中断挂起等待下一个时间片。

    1.3 PCB

    PCB - 进程控制块(Processing Control Block),Linux内核的进程控制块是task_struct结构体。

    理解该结构体中包含的如下信息:

    • 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。
      • 相当于身份证号, 唯一的
      • 类型: pid_t, 正整数
    • 进程的状态,有就绪、运行、挂起、停止等状态。
    • 进程切换时需要保存和恢复数据的一些CPU寄存器。
    • 描述虚拟地址空间的信息。
    • 描述控制终端的信息。
    • 当前工作目录(Current Working Directory)。
      • 进程是在哪个目录下启动的, 这个目录就是当前进程的工作目录
    • umask掩码。
      • umask函数可以调用
    • 文件描述符表,包含很多指向file结构体的指针。
      • 每个进程都有一个属于自己的文件描述符表
    • 和信号相关的信息。
    • 用户id和组id。
      • 进程是哪个用户下启动的就属于哪个用户
      • 有对应的api函数可以获取到这些信息
    • 会话(Session)和进程组。
    • 进程可以使用的资源上限(Resource Limit)。
    • ulimit -a

    1.4 进程状态

    进程有五种状态, 分别是: 创建态, 就绪态, 运行态, 阻塞态, 退出态。

    • 创建态 == 初始态
    • 阻塞态 == 挂起态

    在这里插入图片描述

    创建态: 进程从无到有的过程, 加载资源并初始化
    	- 进程被创建完毕 -> 就绪态
    
    就绪态: 进程已经存在了, 但是不能运行, 因为没有cpu资源
    	- 抢到cpu碎片 -> 运行态
    	
    运行态: 正常的进程, 并且拥有cpu资源, 可以运行
    	- 抢到cpu碎片时间用完, 失去cpu -> 就绪态
    	- 通过外力让进程时间碎片没有用完的情况下失去cpu, 比如: sleep(100) -> 阻塞态(挂起态)
    		
    阻塞态: 通过外力让进程时间碎片没有用完的情况下失去cpu, 在特定的时机下才能解除阻塞
    	- 通过某事操作, 让进程失去cpu
    	- 当某些条件满足, 才会解除阻塞
    		比如: sleep(100)之后, 睡醒了 -> 就绪态
    	
    退出态: 进程被销毁, 进程占用的所有系统资源全部被释放
    	- 就绪, 运行, 挂起态时都可以直接退出
    
    

    2. 进程创建

    2.1 进程ID

    2.1.1 命令

    • 查看进程

      ps aux / ajx
      	a: 显示当前终端下的所有的程序, 包括所有的用户
      	u: 显示用户信息
      	x: 打印和tty终端相关的信息
      	j: 显示更多的用户信息
      
    • 杀死进程

      # 命令, 9代表的九号信号
      kill -9 进程ID
      kill -SIGKILL 进程ID
      #linux中的信号
      $ kill -l
       1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
       6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
      11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
      16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
      21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
      26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
      31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
      38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
      43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTM IN+13
      48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
      53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
      58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
      63) SIGRTMAX-1  64) SIGRTMAX
      

    2.1.2 函数

    • 获取当前进程的进程ID

    • 获取当前进程父进程的进程ID

      #include <sys/types.h>
      #include <unistd.h>
      
      pid_t getpid(void);		// 当前进程
      pid_t getppid(void); 	// 当前进程的父进程
      

    2.2 进程的创建

    • 如何在程序中创建进程?

      #include <unistd.h>
      // 返回值是进程ID
      // 返回两个值:
      // 	- 一个是父进程的: 返回值 > 0
      //  - 一个是子进程的: 返回值 == 0
      pid_t fork(void);
      

    在这里插入图片描述

    • 子进程创建成功之后,代码从什么位置执行?

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

    • 如何区分父子进程?

      fork返回值:
      	pid_t pid > 0: 父进程
      	pid_t pid == 0: 子进程
      

    2.3 父子进程

    1.区别
    	- pcb中存储的进程ID不同
    	- 进程的状态
    	- 寄存器数据信息
    2.共同点
    2.1.当子进程被fork创建之后, 还没有进行任何操作之前, 父子进程用户区数据是完全相同的的
      	- 父子进程各自进行代码处理, 用户区数据会发生变化, 变得不一样了
    2.2.内核区:
      	- 文件描述符表是相同的
      
    3.父子进程对变量是不是共享的?
        - 不能共享
        - 进程和进程之间的数据是相互独立的, 一个进程数据变化对其他进程内部数据没有影响(父子进程)
        - 如果子进程被创建, 父子进程里边的变量都`没有进行写操作`
          - 这两个进程中的同名数据共用同一块内存
        - 如果子进程被创建, 父子进程里边的变量`进行了写操作`
          - 这两个进程中的同名数据使用的不是同一块内存  
    

    在这里插入图片描述

    3. 多进程的gdb调试

    • 默认gdb跟踪的是父进程

    • 切换命令 -> 在启动gdb的时候设置

      # 设置跟踪子进程
      set follow-fork-mode child
      # 设置跟踪父进程
      set follow-fork-mode parent
      

    4. exec族函数

    exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。

    exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段数据段堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样,颇有些神似"三十六计"中的"金蝉脱壳"。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回一个-1,从原程序的调用点接着往下执行。

    // 使用exec族函数, 创建的进程的个数?
    /*
    使用思路:
    - 父进程: 处理对应的逻辑
    - 在合适的时机, 由父进程创建子进程: fork()
    	- 子进程中的代码和父进程中的代码完全相同
    - 在子进程中调用exec函数, 启动另一个磁盘程序a.out
    	- 子进程中的代码被替换了, 变成了a.out中的代码
    		- 栈区, 堆区, 全局数据区, 共享库区都会发生变化
    	- 这个时候子进程就不受父进程控制了
    */
    
    #include <unistd.h>
    extern char **environ;
    
    //ps aux
    
    // 经常使用
    // 使用这个函数启动自己编译得到的可执行程序
    int execl(const char *path, const char *arg, ...);
    参数: 
    - path: 要启动的磁盘程序对应的路径, 建议使用`绝对路径`
    - arg: 要启动的可执行程序的参数;参数结束, NULL作为最后一个参数
    	- 第二个参数对应的arg: 名字随便写, 这个名字出现在ps aux 出现在COMMAND这一列(第二个参数一般和第一个参数相同)
    	- 从第三个arg开始就是可执行程序的实际参数
    	- 最后一个arg,NULL
    
    // 启动由操作系统提供的可执行程序使用该函数
    int execlp(const char *file, const char *arg, ...);
    参数:
    	- file: 只需要指定程序名, 程序会自动搜索环境变量PATH
    	- arg: 要启动的可执行程序的参数;参数结束, NULL作为最后一个参数
    		- 第二个参数对应的arg: 名字随便写, 这个名字出现在ps aux 出现在COMMAND这一列
    		- 从第三个arg开始就是可执行程序的实际参数
    		- 最后一个arg,NULL
    		
    
      	理解	/
    		
    int execle(const char *path, const char *arg, ..., char *const envp[]);
    参数:
    	- path: 要启动的程序的名字
    	- arg: 要启动的可执行程序的参数;参数结束, NULL作为最后一个参数
    		- 第二个参数对应的arg: 名字随便写, 这个名字出现在ps aux 出现在COMMAND这一列
    		- 从第三个arg开始就是可执行程序的实际参数
    		- 最后一个arg,NULL
    	- envp: 第一个参数对应的程序名去当前参数指定的目录下搜索
    		char* envp[] = {"/bin", "/home/robin", NULL};
    
    // 使用这个函数启动自己编译得到的可执行程序
    int execv(const char *path, char *const argv[]);
    参数:
    	- path: 要启动程序的绝对路径
    	- argv: 要启动的程序的参数
    		char* args[] = {"123", "hello", "world", NULL};
    
    // 启动由操作系统提供的可执行程序使用该函数
    int execvp(const char *file, char *const argv[]);
    参数:
    	- file: 文件名, 程序会自动搜索环境变量PATH
    	- argv: 要启动的程序的参数
    		char* args[] = {"123", "hello", "world", NULL};
    
    // 只有这个函数才是系统函数, 前五个都不是
    int execvpe(const char *file, char *const argv[], char *const envp[]);
    参数:
    	- file: 写个文件名就可以, 要启动的程序
    	- argv: 要启动的程序的参数
    		char* args[] = {"123", "hello", "world", NULL};
    	- envp: 第一个参数对应的程序名去当前参数指定的目录下搜索
    		char* envp[] = {"/bin", "/home/robin", NULL};
    
    l(list)参数地址列表,以空指针结尾
    v(vector)存有各参数地址的指针数组的地址
    p(path)按 PATH 环境变量指定的目录搜索可执行文件
    e(environment)存有环境变量字符串地址的指针数组的地址

    Qt中的exec族函数

    QDialog dlg;
    dlg.exec();	// 阻塞
    

    5. 进程控制

    每个进程结束之后, 都会自己释放自己地址空间中的 用户区 数据, 内核区的pcb没有办法自己释放掉, 需要父进程去释放.

    5.1 结束进程

    int main()
    {
        int num = func();
        return 0;
    }
    
    int func()
    {
        return 0;
    }
    
    在main函数中直接调用return函数可以退出进程
    如果不是在main函数中return, 则程序返回到调用者的位置
    
    // exit -> c库函数
    #include <stdlib.h>
    void exit(int status);
    exit(-1);
    
    // _exit() -> linux系统函数
    #include <unistd.h>
    void _exit(int status);
    
    

    5.2 孤儿进程

    父进程创建子进程, 父进程退出了, 子进程还在

    操作系统中PID==1的进程会收养这个没有父亲的子进程

    为什么要领养?

    • 所有进程的内核区的PCB资源自己无法释放, 必须要由父进程完成该操作

    5.3 僵尸进程

    首先有一个父进程, 创建了子进程

    • 子进程先死, 父进程一直活着
    • 父进程不负责任, 不去释放子进程的PCB资源
      • 这个时候的子进程称之为: 僵尸进程
      • 使用 kill -9 杀不死僵尸进程

    5.3 进程回收 wait waitpid

    #include <sys/types.h>
    #include <sys/wait.h>	// 主要加这个
    
    // 阻塞函数, 停到调用该函数的位置, 不会继续执行, 时机成熟之后继续执行
    // 当子进程死亡之后, 该函数解除阻塞
    // 该函数调用一次只能回收一个子进程资源
    // 当前没有子进程之后, 函数解除阻塞, 调用一次, 返回-1
    pid_t wait(int *status);
    参数:
    	- status: 死亡的子进程的状态信息, 一般该参数不用, 直接写NULL
    返回值:
    	成功: 被资源回收的子进程的进程PID
    	失败: -1
    
    // 可以设置阻塞, 也可以设置为非阻塞    
    // 可以指定回收那个子进程资源
    // 该函数调用一次只能回收一个子进程资源
    // 如果该函数设置为阻塞, 当前没有子进程之后, 函数解除阻塞, 调用一次, 返回-1
    pid_t waitpid(pid_t pid, int *status, int options);
    // pid_t pid = waitpid(-1,NULL,WNOHANG)
    参数:
    - pid: 
    	- >0: 某个进程的PID, 要回收那个进程就把哪个进程的PID写到这-> 经常用
    	- ==0: 回收当前进程组中的所有子进程的资源
    			只回收,本组内的自己的孩子
    	- ==-1: 回收所有的子进程的资源							-> 经常用
    			只要是自己的孩子,不论是否被送人,都回收
    	- < 0: 回收送到其他组的子进程进程资源, 进程ID取反(比如: 12345), 因此 == -12345
                自己的孩子&&被送到其他的组了,回收
    - status: 记录进程退出的状态, 一般写NULL
    - options:
    	- 0: 该函数阻塞
    	- WNOHANG: 函数非阻塞
    返回值:
    	- >0: 成功回收的子进程对应的进程ID
    	- -1: 失败
    	- ==0: 该函数如果是非阻塞状态, 代表当前父进程还有子进程在运行
    	
    	
    // 写程序:
    在父进程中创建5个子进程, 使用waitpid回收这些子进程资源
    // 这是错误的, 创建出的子进程个数>5
    // 如果是子进程, 不要再创建子进程了
    for(int i=0; i<5; ++i)
    {
        pid_t pid = fork();
        if(0 == pid)
        {
            break;
        }
    }
    

    6. dup,dup2,fcntl函数

    6.1 dup和dup2

    #include <unistd.h>
    // 复制文件描述符, 参数 old_fd 就是要复制的文件描述符
    // 返回值  :被复制出的 new_fd 文件描述符
    // 结论	:通过返回值和参数都能访问到同一个磁盘文件
    int dup(int oldfd);
    
    // 测试程序
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    
    int main()
    {
        // 打开文件
        int fd = open("a.txt", O_RDWR|O_CREAT, 0664);
        if(fd == -1)
        {
            perror("open");
            return 0;
        }
    
        // 复制文件描述符
        int fd1 = dup(fd);
        // 关闭fd
        close(fd);
        // 写文件
        char* str = "hello, world";
        write(fd1, str, strlen(str));
        close(fd1);
    
        return 0;
    }
    
    // 要求: oldfd必须是一个有效的文件描述法, 指向某一个已经存在的磁盘文件
    /*
    1.可以复制文件描述符
    	- 参数newfd, 没有指向一个有效的磁盘文件
    	- 通过dup2可以让newfd指向oldfd对应的磁盘文件
    
    2.可以重定向文件描述符
    	- newfd指向磁盘文件A, oldfd指向磁盘文件B
    	- 通过调用dup2
    		- newfd和磁盘文件A断开连接, 同时指向了磁盘文件B
    */
    // 如果newfd == oldfd, 相当于什么也没干
    int dup2(int oldfd, int newfd);
    
    // 测试代码
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    
    int main()
    {
        // 打开文件
        int fd = open("a.txt", O_RDWR|O_CREAT, 0664);
        if(fd == -1)
        {
            perror("open");
            return 0;
        }
    
        int fd1 = open("b.txt", O_RDWR|O_CREAT, 0664);
        if(fd1 == -1)
        {
            perror("open");
            return 0;
        }
        
        int fd3 = 6;
    #if 0
        // 重定向文件描述符
        dup2(fd, fd1);
    #else
        // 文件描述符复制
        dup2(fd, fd3);
    #endif
        close(fd);
    
        // 写文件
        char* str = "你好, 世界";
    #if 0
        write(fd1, str, strlen(str));
        close(fd1);
    #else
        write(fd3, str, strlen(str));
        close(fd3);
    #endif
    
    
        return 0;
    }
    

    6.2 fcntl函数

    // 控制函数
    #include <unistd.h>
    #include <fcntl.h>
    int fcntl(int fd, int cmd, ... /* arg */ );
    
    //复制文件描述符: 函数的第二个参数cmd: F_DUPFD
    int newfd = fcntl(fd, F_DUPFD);
    
    //修改文件的属性, 不是所有的属性都可以追加, 只能对一些附属属性进行追加/删除操作
    //	- O_APPEND, 在文件尾部追加数据
    //	- O_NONBLOCK, 设置为非阻塞
    
    //使用步骤
    //  1.int open(const char *pathname, int flags);
    //    int fd = open("a", O_WRONLY);
    //  2.得到原来设置好的属性信息: 第二个参数cmd: F_GETFL
    //    int flag = fcntl(fd, F_GETFL);
    //  3.追加属性
    //    flag = flag | O_APPEND;
    //  4.将新的属性设置给文件描述符: 第二个参数cmd: F_SETFL
    //    fcntl(fd, F_SETFL, flag);
    
    // 测试代码
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    
    int main()
    {
        // 打开文件
        int fd = open("a.txt", O_RDWR|O_CREAT, 0664);
        if(fd == -1)
        {
            perror("open");
            return 0;
        }
    
        // fd添加追加数据的属性
        int flag = fcntl(fd, F_GETFL);
        //flag = flag | O_APPEND;
        flag |= O_APPEND;
        fcntl(fd, F_SETFL, flag);
    
        // 写文件
        char* str = "我是要成为海贼王的男人...";
        write(fd, str, strlen(str));
        close(fd);
    
        return 0;
    }
    
    展开全文
  • python开发工程师考证试题选择题题目关于 Python 程序格式框架的描述,以下选项中错误的是 ( A )A: Python 语言不采用严格的“缩进”来表明程序的格式框架B: Python 单层缩进代码属于之前最邻近的一行非缩进代码,...

    python开发工程师考证试题

    选择题

    题目

    关于 Python 程序格式框架的描述,以下选项中错误的是 ( A )

    A: Python 语言不采用严格的“缩进”来表明程序的格式框架

    B: Python 单层缩进代码属于之前最邻近的一行非缩进代码,多层缩进代码根据缩进关系决定所属范围

    C: Python 语言的缩进可以采用 Tab 键实现

    D: 判断、循环、函数等语法形式能够通过缩进包含一批 Python 代码,进而表达对应的语义

    IDLE环境的退出命令是 ( A )

    A: exit

    B: 回车键

    C: close

    D: esc

    关于Python循环结构,以下选项中描述错误的是 ( A )

    A: 每个continue语句只有能力跳出当前层次的循环

    B: break用来跳出最内层for或者while循环,脱离该循环后程序从循环代码后继续执行

    C: 遍历循环中的遍历结构可以是字符串、文件、组合数据类型和range函数等

    D: Python通过for、while等保留字提供遍历循环和无限循环结构

    关于Python的lambda函数,以下选项中描述错误的是 ( B )

    A: lambda函数将函数名作为函数结果返回

    B: f = lambda x,y:x+y 执行后,f的类型为数字类型 (function类型)

    C: lambda用于定义简单的、能够在一行内表示的函数

    D: 可以使用lambda函数定义列表的排序原则

    以下选项中,不是Python对文件的打开模式的是 ( D )

    A: 'r'

    B: '+'

    C: 'w'

    D: 'c'

    以下选项中,不是 Python 语言保留字的是 ( A )

    A: do

    B: pass

    C: except

    D: while

    关于Python赋值语句,以下选项中不合法的是 ( C )

    A: x=1;y=1

    B: x=y=1

    C: x=(y=1)

    D: x,y=y,x

    以下选项中,不是Python IDE的是 ( D )

    A: PyCharm

    B: Jupyter Notebook

    C: Spyder

    D: R studio

    random库中用于生成随机小数的函数是 ( A )

    A: random

    B: randint

    C: getrandbits

    D: randrange

    以下选项中,不属于函数的作用的是 ( A )

    A: 提高代码执行速度

    B: 降低编程复杂度

    C: 增强代码可读性

    D: 复用代码

    关于Python文件打开模式的描述,以下选项中错误的是 ( C )

    A: 只读模式r

    B: 追加写模式a

    C: 创建写模式n

    D: 覆盖写模式w

    time库的time.time函数的作用是 ( D )

    A: 返回系统当前时间戳对应的易读字符串表示

    B: 返回系统当前时间戳对应的struct_time对象

    C: 返回系统当前时间戳对应的本地时间的struct_time对象,本地之间经过时区转换

    D: 返回系统当前的时间戳

    关于函数的可变参数,可变参数*args传入函数时存储的类型是( B )

    A: dict

    B: tuple

    C: list

    D: set

    关于形参和实参的描述,以下选项中正确的是( D )

    A: 函数定义中参数列表里面的参数是实际参数,简称实参

    B: 参数列表中给出要传入函数内部的参数,这类参数称为形式参数,简称形参

    C: 程序在调用时,将形参复制给函数的实参

    D: 函数调用时,实参默认采用按照位置顺序的方式传递给函数,Python也提供了按照形参名称输入实参的方式

    Python语句:f = open,以下选项中对f的描述错误的是 ( B )

    A: *f是文件句柄,用来在程序中表达文件

    B: 表达式print(f)执行将报错

    C: *f是一个Python内部变量类型

    D: 将f当作文件对象,f.read可以读入文件全部信息

    表达式",".join(ls)中ls是列表类型,以下选项中对其功能的描述正确的是 ( D)

    A: 将逗号字符串增加到列表ls中

    B: 在列表ls每个元素后增加一个逗号

    C: 将列表所有元素连接成一个字符串,每个元素后增加一个逗号

    D: 将列表所有元素连接成一个字符串,元素之间增加一个逗号

    以下选项中,不是Python文件处理.seek方法的参数是( C )

    A: 0

    B: 1

    C: -1

    D: 2

    给定字典d,以下选项中对d.keys的描述正确的是 ( C )

    A: 返回一个列表类型,包括字典d中所有键

    B: 返回一个集合类型,包括字典d中所有键

    C: 返回一种dict_keys类型,包括字典d中所有键

    D: 返回一个元组类型,包括字典d中所有键

    关于Python的元组类型,以下选项中描述错误的是 ( D )

    A: 一个元组可以作为另一个元组的元素,可以采用多级索引获取信息

    B: 元组一旦创建就不能被修改

    C: Python中元组采用逗号和圆括号(可选)来表示

    D: 元组中元素不可以是不同类型

    关于函数的关键字参数使用限制,以下选项中描述错误的是 ( A )

    A: 关键字参数必须位于位置参数之前

    B: 不得重复提供实际参数

    C: 关键字参数必须位于位置参数之后

    D: 关键字参数顺序无限制

    关于函数,以下选项中描述错误的是 ( A )

    A: 函数名称不可赋给其他变量

    B: 一条函数定义定义一个用户自定义函数对象

    C: 函数也是数据

    D: 函数定义语句可执行

    关于函数的参数,以下选项中描述错误的是 ( A )

    A: 可选参数可以定义在非可选参数的前面

    B: 一个元组可以传递给带有星号的可变参数

    C: 在定义函数时,可以设计可变数量参数,通过在参数前增加星号(*)实现

    D: 在定义函数时,如果有些参数存在默认值,可以在定义函数时直接为这些参数指定默认值

    以下选项中,对于函数的定义错误的是 ( A )

    A: def vfunc(*a,b):

    B: def vfunc(a,b):

    C: def vfunc(a,*b):

    D: def vfunc(a,b=2):

    关于lambda函数,以下选项中描述错误的是 ( A )

    A: lambda不是Python的保留字

    B: lambda函数也称为匿名函数

    C: lambda函数将函数名作为函数结果返回

    D: 定义了一种特殊的函数

    以下选项中,不属于关系型数据库的是(D)

    A:Mysql

    B:Oracel

    C:Microsoft SQL Server

    D:MongoDB

    以下关于字典的描述,错误的是(D)

    B. 字典长度是可变的

    C. 字典是键值对的集合

    D. 字典中的键可以对应多个值信息

    以下属于 Python 脚本程序转变为可执行程序的第三方库的是(D)

    A. openpyxl

    B. PyPDF2

    C. pillow

    D. pyinstaller

    以下关于 Python 函数对变量的作用,错误的是(D)

    A. 简单数据类型在函数内部用 global 保留字声明后,函数退出后该变量保留

    B. 全局变量指在函数之外定义的变量,在程序执行全过程有效

    C. 简单数据类型变量仅在函数内部创建和使用,函数退出后变量被释放

    D. 对于组合数据类型的全局变量,如果在函数内部没有被真实创建的同名变量,则函数内部不可以直接使用并修改全局变量的值

    以下关于列表和字符串的描述,错误的是(D)

    A. 列表使用正向递增序号和反向递减序号的索引体系

    B. 列表是一个可以修改数据项的序列类型

    C. 字符和列表均支持成员关系操作符(in)和长度计算函数(len)

    D. 字符串是单一字符的无序组合

    以下 Python 语言关键字在异常处理结构中用来捕获特定类型异常的选项是(D)

    A. for

    B. lambda

    C. in

    D. expect

    Python 语言中,以下表达式输出结果为 11 的选项是(D)

    A. print("1+1")

    B. print(1+1)

    C. print(eval("1+1"))

    D. print(eval("1" + "1"))

    以下属于python多线程的模块的选项为(D)

    A:multiprocessing

    B:gevent

    C:asyncio

    D:threading

    下列选项中,不属于Python语言特点的是(C)。

    A.简单易学

    B.开源

    C.面对过程

    D.可移植性

    假设list1是[2,33,222,14,25],什么是list1 [-1]. (C)

    A:错误

    B:没有

    C:25

    D:2

    何时执行try-except-else的else部分?(c)

    A:总是

    B:发生异常时

    C:没有异常发生时

    D:没有else语法

    为什么不鼓励以下划线开头的局部变量名?(A)

    A:它们用于表示类的私有变量

    B:他们混淆了口译员

    C:它们用于表示全局变量

    D:他们放慢执行速度

    以下哪项是无效声明?(B)

    A:abc = 1,000,000

    B:a b c = 1000 2000 3000

    C:a,b,c = 1000,2000,3000

    D:a_b_c = 1,000,000

    以下不属于HTTP请求库的选项为(B)

    A:urllib

    B:BeautifulSoup

    C:requests

    D:aiohttp

    以下选项中不符合 Python 语言变量命名规则的是(B)

    A.I

    B.3_1

    C._AI

    D.TempStr

    以下关于 Python 字符串的描述中,错误的是(C)

    A.字符串是字符的序列,可以按照单个字符或者字符片段进行索引

    B.字符串包括两种序号体系:正向递增和反向递减

    C.Python 字符串提供区间访问方式,采用 [N:M] 格式,表示字符串中从 N 到 M 的索引子字符串(包含 N 和 M)

    D.字符串是用一对双引号" "或者单引号‘ ‘括起来的零个或者多个字符

    关于 import 引用,以下选项中描述错误的是(B)

    A.使用 import turtle 引入turtle 库

    B.可以使用 from turtle import setup 引入 turtle 库

    C.使用 import turtle as t 引入 turtle 库,取别名为 t

    D.import 保留字用于导入模块或者模块中的对象

    关于程序的异常处理,以下选项中描述错误的是(C)

    A.程序异常发生经过妥善处理可以继续执行

    B.异常语句可以与 else 和 finally 保留字配合使用

    C.编程语言中的异常和错误是完全相同的概念

    D.Python 通过 try、except 等保留字提供异常处理功能

    关于函数,以下选项中描述错误的是(C)

    A.函数能完成特定的功能,对函数的使用不需要了解函数内部实现原理,只要了解函数的输入输出方式即可。

    B.使用函数的主要目的是减低编程难度和代码重用

    C.Python 使用 del 保留字定义一个函数

    D.函数是一段具有特定功能的、可重用的语句组

    28. 以下选项中是 Python 中文分词的第三方库的是(A)

    A.jieba

    B.itchat

    C.time

    D.turtle

    关于 Python 对文件的处理,以下选项中描述错误的是(B)

    A.Python 通过解释器内置的 open 函数打开一个文件

    B.当文件以文本方式打开时,读写按照字节流方式

    C.文件使用结束后要用 close 方法关闭,释放文件的使用授权

    D.Python 能够以文本和二进制两种方式处理文件

    关于 Python 字符编码,以下选项中描述错误的是(D)

    A.chr(x) 和 ord(x) 函数用于在单字符和 Unicode 编码值之间进行转换

    B.print(chr(65)) 输出 A

    C.print(ord(‘a‘)) 输出 97

    D.Python 字符编码使用 ASCII 编码

    关于 Python 循环结构,以下选项中描述错误的是(B)

    A.遍历循环中的遍历结构可以是字符串、文件、组合数据类型和 range 函数等

    B.break 用来结束当前当次语句,但不跳出当前的循环体

    C.continue 只结束本次循环

    django是一个(A)模式框架。

    A: MTV

    B: MVC

    C:WSGI

    D:ISO

    在下列Django的ORM操作方法中,哪一个不会返回QuerySet对象?D

    A:all

    B:filter

    C:exclude

    D:get

    在下列Django的ORM操作方法中,当匹配不到数据时,哪一个会报错?B

    A:all

    B:get

    C:exclude

    D:filter

    下列选项不是Django框架提供的表单对象的功能的是(D)

    A:渲染

    B:校验数据

    C:解耦

    D:混淆代码

    以下哪个不是redis数据库的数据类型(C)

    A:string

    B:list

    C:dict

    D:set

    以下说法正确的是:A

    A:cookie信息是存储在客户端的

    B:session信息是存储在客户端的

    C:cookie技术仅有客户端实现

    D:session技术不依赖cookie技术

    以下说法错误的是:D

    A:在django框架中,通过post表单提交的数据可以使用request.POST获取

    B:在django框架中,通过url参数提交的数据可以使用request.GET获取

    C:在django框架中,通过路径参数提交的数据可以使用视图函数的参数获取

    D:在django框架中,通过post提交的json数据可以使用request.POST获取

    生产环境下,django项目配置文件中的DEBUG属性应该设置为:D

    A: 1

    B:0

    C:None

    D:True

    在某个django框架中定义了一个Student的模型,它用来表示学生表,以下字段定义错误的是: A

    A: name = models.CharField('姓名')

    B: age = models.SmallIntergerField('年龄', null=True, blank=True)

    C: mobile = models.CharFied('电话', max_length=11, min_length=11)

    D: qq = models.CharField(max_length=20)

    Django框架中,中间件的作用非常大,以下说法错误的是:D

    A: 中间件可以在视图处理前处理请求对象

    B: 中间件可以在视图处理结束后处理响应对象

    C: 中间件可以在请求处理前处理请求对象

    D: 中间件可以在视图处理中处理请求对象

    以下不属于requests模块response对象的方法的是(D)

    A:content

    B:text

    C:json

    D:read

    TCP协议建立连接需要多次握手?(C)

    A:一次

    B:二次

    C:三次

    D:四次

    TCP协议断开连接需要多次挥手?(D)

    A:一次

    B:二次

    C:三次

    D:四次

    以下选项中不属于网页解析库的是(C)

    A:re

    B:lxml

    C:requests

    D:BeautifuiSoup

    redis中数据库默认是多少个db?(C)

    A:10个

    B:15个

    C:16个

    D:20个

    下列选项中,不属于django内置组件的是?(B)

    A:admin

    B:xadmin

    C:model

    D:form

    问答题

    1.声明变量注意事项有哪些?

    1)由字母、数字和下划线构成,不能以数字开头,不能任意特殊字符

    2)变量定义规范,使用驼峰式或者下划线式格式

    3)变量定义尽量简明,易懂,方便使用者应用

    2.如何查看变量在内存中的地址?

    可以通过id方法,获取变量在内存中的地址,例如 name = 456789 print(id(name))

    3.Python单行注释和多行注释分别用什么?

    单行注释: # 被注释内容

    多行注释: ''' 被注释内容 '''

    4.什么是lambda函数?

    lambda是Python中的匿名函数。它语法简单,简化代码,不会产生命名冲突,污染命名空间。

    5.列表和元组有什么区别?

    列表是可变的,即可以编辑。元组是不可变的(元组是无法编辑的列表)。

    6.Python中的字典是什么?

    python中的内置数据类型称为字典。它定义了键和值之间的one-to-one关系。

    字典包含一对键及其对应的值。字典由键来索引。

    7.什么是Python中的map函数

    Map函数执行作为第一个参数给出的函数,该函数遍历第二个参数给出的迭代的所有元素的

    8.深拷贝和浅拷贝有什么区别?

    浅拷贝用于复制引用指针,就像复制值一样。

    深层复制不会将引用指针复制到对象。它引用一个对象,并存储一些其他对象指向的新对象。

    9.Python中 help函数的用途是什么?

    help函数用于显示文档字符串,还可以帮助您查看与模块,关键字,属性等相关的帮助。

    10.Python中dir函数的用途是什么?

    dir返回参数的属性、方法列表mm

    11.什么是线程同步?

    多个线程同时访问同一资源,等待资源访问结束,浪费时间,效率低

    12.redis有哪些数据类型?

    string list hash set zset

    13.scrapy中间件有哪几种类?

    下载中间件和爬虫中间件

    14.装饰器的作用 ?

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,提高了代码的复用性。

    15.json模块中load和loads有什么区别?

    load是将json格式的字符转换为dict,loads是将string转换为dict。

    16.什么是无头浏览器?

    无头浏览器即headless browser,是一种没有界面的浏览器。既然是浏览器那么浏览器该有的东西它都应该有,只是看不到界面而已。

    17.什么是递归?

    在调用一个函数的过程中,直接或间接地调用了函数本身这个就叫递归。

    18.什么是生成器?

    生成器会生成一系列的值用于迭代,这样看它又是一种可迭代对象。它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。

    19.什么是迭代器?

    迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。

    20.Python中的split函数的作用?

    Split能让我们用指定字符分割字符串。

    21.如何判断是函数还是方法?

    通过type可以知道对象所属的类型,函数是,方法是

    22.isinstance的作用?

    isinstance 函数来判断一个对象是否是一个已知的类型,类似 type。

    23.json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

    序列化的时候,加入ensure_ascii参数

    24.yield关键字的作用?

    当一个函数中存在yield关键字时,它就变成了一个生成器,每次迭代求值一次,节省内存;

    25.pass语句的作用是什么?

    pass是空语句占位符,是为了保持程序结构的完整性。

    26.is和==的区别是什么?

    在python中,is检查两个对象是否是同一个对象,而==检查他们的值是否相等.

    27.mysql数据库的约束有哪些?

    主键约束、唯一约束、检查约束、非空约束、外键约束

    28.事务的特性有哪些?

    Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)

    29.mysql中主键和外键的区别?

    主键是能确定一条记录的唯一标示。例如,身份证证号

    外键:用于与另一张表的关联,是能确定另一张表记录的字段,用于保持数据的一致性

    30.redis中不同db的作用?

    Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。

    31.scrapy和scrapy-redis的区别?

    scrapy是一个爬虫通用框架,但不支持分布式,scrapy-redis是为了更方便的实现scrapy分布式爬虫,而提供了一些以redis为基础的组件

    32.python语言中enumerate的意思是?

    对于一个可迭代的(iterable)/可遍历的对象(如列表、字符串),enumerate将其组成一个索引序列,利用它可以同时获得索引和值

    enumerate多用于在for循环中得到计数

    33.多进程更稳定还是多线程更稳定?为什么?

    多进程更稳定,它们是独立运行的,不会因为一个崩溃而影响其他进程。

    34.HTTP协议请求由什么组成?

    请求行(request line)、请求头部(header)、空行和请求数据四个部分组成

    35.https协议和http协议有什么区别?

    http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

    36.Django框架中的MTV模式,具体指什么?

    Django框架的MTV设计模式借鉴了MVC框架的思想,三部分为:Model、Template和View

    37.什么是wsgi和uwsgi?

    wsgi是web服务器网关接口,是一套协议。用于接收用户请求并将请求进行初次封装,然后将请求交给web框架

    uwsgi与WSGI一样是一种通信协议,它是uWSGI服务器的独占协议,用于定义传输信息的类型

    38.django中csrf的实现机制

    第一步:django第一次响应来自某个客户端的请求时,后端随机产生一个token值,把这个token保存在SESSION状态中;同时,后端把这个token放到cookie中交给前端页面;

    第二步:下次前端需要发起请求(比如发帖)的时候把这个token值加入到请求数据或者头信息中,一起传给后端;Cookies:{csrftoken:xxxxx}

    第三步:后端校验前端请求带过来的token和SESSION里的token是否一致;

    展开全文
  • 答:前趋图(Precedence Graph)是一个有向无循环图,记为DAG(DirectedAcyclicGraph),用于描述进程之间执行的前后关系。 2.画出下面四条语句的前趋图: S1:a=x+y; S2:b=z+1; S3:c=a – b;S4:w=c+1; 3. 什么程序...

    1.什么是前趋图?为什么要引入前趋图?

    答:前趋图(Precedence Graph)是一个有向无循环图,记为DAG(DirectedAcyclicGraph),用于描述进程之间执行的前后关系。

    2.画出下面四条语句的前趋图:

    S1:a=x+y; S2:b=z+1; S3:c=a – b;S4:w=c+1;
    在这里插入图片描述
    3. 什么程序并发执行会产生间断性特征?

    答:程序在并发执行时,由于它们共享系统资源,为完成同一项任务需要相互合作,致使这些并发执行的进程之间,形成了相互制约关系,从而使得进程在执行期间出现间断性。

    4.程序并发执行时为什么会失去封闭性和可再现性?

    答:程序并发执行时,多个程序共享系统中的各种资源,因而这些资源的状态由多个程序改变,致使程序运行失去了封闭性,也会导致其失去可再现性。

    5.在操作系统中为什么要引入进程概念?它会产生什么样的影响?

    答:为了使程序在多道程序环境下能并发执行,并对并发执行的程序加以控制和描述,在操作系统中引入了进程概念。

    影响: 使程序的并发执行得以实行。

    6.试从动态性,并发性和独立性上比较进程和程序?

    答:(1)动态性是进程最基本的特性,表现为由创建而产生,由调度而执行,因得不到资源而暂停执行,由撤销而消亡。进程有一定的生命期,而程序只是一组有序的指令集合,是静态实体。

    (2)并发性是进程的重要特征,同时也是OS 的重要特征。引入进程的目的正是为了使
    其程序能和其它进程的程序并发执行,而程序是不能并发执行的。

    (3)独立性是指进程实体是一个能独立运行的基本单位,也是系统中独立获得资源和独立调度的基本单位。对于未建立任何进程的程序,不能作为独立单位参加运行。

    7.试说明PCB 的作用,为什么说PCB 是进程存在的惟一标志?

    答:PCB 是进程实体的一部分,是操作系统中最重要的记录型数据结构。作用是使一个在多道程序环境下不能独立运行的程序,成为一个能独立运行的基本单位,成为能与其它进程并发执行的进程。OS是根据PCB对并发执行的进程进行控制和管理的。

    11.试说明进程在三个基本状态之间转换的典型原因。

    答:(1)就绪状态→执行状态:进程分配到CPU资源

    (2)执行状态→就绪状态:时间片用完

    (3)执行状态→阻塞状态:I/O请求

    (4)阻塞状态→就绪状态:I/O完成

    12.为什么要引入挂起状态?该状态有哪些性质?

    答:引入挂起状态处于五种不同的需要: 终端用户需要,父进程需要,操作系统需要,对换需要和负荷调节需要。处于挂起状态的进程不能接收处理机调度。

    13.在进行进程切换时,所要保存的处理机状态信息有哪些?

    答:进行进程切换时,所要保存的处理机状态信息有:

    (1)进程当前暂存信息

    (2)下一指令地址信息

    (3)进程状态信息

    (4)过程和系统调用参数及调用地址信息。

    14.试说明引起进程创建的主要事件。

    答:引起进程创建的主要事件有:用户登录、作业调度、提供服务、应用请求。

    15.试说明引起进程被撤销的主要事件。

    答:引起进程被撤销的主要事件有:正常结束、异常结束(越界错误、保护错、非法指令、特权指令错、运行超时、等待超时、算术运算错、I/O 故障)、外界干预(操作员或操作系统干预、父进程请求、父进程终止)。

    16.在创建一个进程时所要完成的主要工作是什么?

    答:

    (1)OS 发现请求创建新进程事件后,调用进程创建原语Creat();

    (2)申请空白PCB;

    (3)为新进程分配资源;

    (4)初始化进程控制块;

    (5)将新进程插入就绪队列.

    17.在撤销一个进程时所要完成的主要工作是什么?

    答:

    (1)根据被终止进程标识符,从PCB 集中检索出进程PCB,读出该进程状态。

    (2)若被终止进程处于执行状态,立即终止该进程的执行,置调度标志真,指示该进程被终止后重新调度。

    (3)若该进程还有子进程,应将所有子孙进程终止,以防它们成为不可控进程。

    (4)将被终止进程拥有的全部资源,归还给父进程,或归还给系统。

    (5)将被终止进程PCB 从所在队列或列表中移出,等待其它程序搜集信息。

    18.试说明引起进程阻塞或被唤醒的主要事件是什么?

    答:a. 请求系统服务;b. 启动某种操作;c. 新数据尚未到达;d. 无新工作可做.

    19.为什么要在OS 中引入线程?

    答:在操作系统中引入线程,则是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性,提高CPU的利用率。进程是分配资源的基本单位,而线程则是系统调度的基本单位。

    20.试说明线程具有哪些属性?

    答:(1)轻型实体(2)独立调度和分派的基本单位(3)可并发执行(4)共享进程资源。

    21.试从调度性,并发性,拥有资源及系统开销方面对进程和线程进行比较。

    答:

    (1)调度性。线程在OS 中作为调度和分派的基本单位,进程只作为资源拥有的基本单位。

    (2)并发性。进程可以并发执行,一个进程的多个线程也可并发执行。

    (3)拥有资源。进程始终是拥有资源的基本单位,线程只拥有运行时必不可少的资源,本身基本不拥有系统资源,但可以访问隶属进程的资源。

    (4)系统开销。操作系统在创建、撤消和切换进程时付出的开销显著大于线程。

    23.何谓用户级线程和内核支持线程?

    答:

    (1)用户级线程:仅存在于用户空间中的线程,无须内核支持。这种线程的创建、撤销、线程间的同步与通信等功能,都无需利用系统调用实现。用户级线程的切换通常发生在一个应用进程的诸多线程之间,同样无需内核支持。

    (2)内核支持线程:在内核支持下运行的线程。无论是用户进程中的线程,还是系统线程中的线程,其创建、撤销和切换等都是依靠内核,在内核空间中实现的。在内核空间里还为每个内核支持线程设置了线程控制块,内核根据该控制块感知某线程的存在并实施控制。

    24.试说明用户级线程的实现方法。

    答:用户级线程是在用户空间中的实现的,运行在“运行时系统”与“内核控制线程”的中间系统上。运行时系统用于管理和控制线程的函数的集合。内核控制线程或轻型进程LWP可通过系统调用获得内核提供服务,利用LWP进程作为中间系统。

    25.试说明内核支持线程的实现方法。

    答:系统在创建新进程时,分配一个任务数据区PTDA,其中包括若干个线程控制块TCB空间。创建一个线程分配一个TCB,有关信息写入TCB,为之分配必要的资源。当PTDA中的TCB 用完,而进程又有新线程时,只要所创建的线程数目未超过系统允许值,系统可在为之分配新的TCB;在撤销一个线程时,也应回收线程的所有资源和TCB。

    展开全文
  • 【操作系统】第六话·线程是进程的(宝ᴗ宝)嘛?

    千次阅读 多人点赞 2022-03-12 15:23:07
    写在前面 Hello大家好啊,我是kikokingzz,名字太长不好记,大家可以叫我kiko哦~ 从今天开始,我们将要...【2019统考真题】下列关于线程的描述中,错误的是( )。 A.内核级线程的调度由操作系统完成 B.操作系统为每...
  • 1、操作系统(推荐查看书籍:现代操作系统)  操作系统是位于计算机硬件...2、进程  一个正在运行的程序或者说是一个程序的运行过程 3、串行、并发、并行  串行:一个任务完完整整运行完毕,才执行下一个程序  ...
  • 操作系统--第二章 进程描述与控制--习题答案

    万次阅读 多人点赞 2020-03-22 09:35:21
    操作系统第四版课后的全部习题答案,学习通作业答案。 说明:操作系统其他章节的习题答案也在此...Graph),用于描述进程之间执行的前后关系。 2. 画出下面6条语句的前趋图(符号“:=”是赋值的意思) S1:a:=x +...
  • Linux之进程管理一

    千次阅读 2022-04-22 10:50:20
    头歌educatorLinux之进程管理一
  • 摘要:本文主要介绍进程的基本属性,基本属性包括:进程ID、父进程ID、进程组ID、会话和控制终端.
  • 进程间传递文件描述

    千次阅读 2016-08-09 20:00:56
    首先,必须声明,“进程间传递文件描述符”这个说法是错误的。 在处理文件时,内核空间和用户空间使用的主要对象是不同的。对用户程序来说,一个文件由一个文件描述符标识。该描述符是一个整数,在所有有关文件的...
  • Linux -- 多进程编程之 - 守护进程

    千次阅读 多人点赞 2021-11-04 22:49:19
    守护进程是一个生存期较长的进程,他常常在系统引导装入是启动,仅仅在系统关闭的才终止。也就是通常所说的 Daemon 进程,是 Linux 中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些...
  • 一文读懂Linux进程进程组、会话、僵尸

    千次阅读 多人点赞 2020-02-24 08:21:00
    :一个进程使用 fork 创建子进程,如果子进程先退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程进程描述符仍然保存在系统中。这种进程称之为僵死进程。 守护进程: (英语:daemon)...
  • Linux进程概念(精讲)

    千次阅读 多人点赞 2021-09-09 08:54:04
    文章目录基本概念描述进程-PCB组织进程查看进程通过系统调用获取进程的PID和PPID通过系统调用创建进程- fork初始进程状态运行状态-R浅度睡眠状态-S深度睡眠状态-D暂停状态-T僵尸状态-Z死亡状态-X僵尸进程僵尸进程的...
  • Linux 进程必知必会

    千次阅读 2020-07-10 08:58:31
    上一篇文章只是简单的描述了一下 Linux 基本概念,通过几个例子来说明 Linux 基本应用程序,然后以 Linux 基本内核构造来结尾。那么本篇文章我们就深入理解一下 Linux 内核来理解 Linux 的基本概念之进程和线程。...
  • Node之创建多进程应用程序

    千次阅读 2020-01-06 22:48:42
    引 在Node.js中,只使用一个线程来执行所有的操作。因此,如果在应用程序中存在某个...近些年来,服务器一般都开始使用多核CPU或者多CPU,许多服务器应用程序都开始依靠多线程或多进程机制来处理这些请求,以便可...
  • Node之进程

    千次阅读 2020-01-05 18:33:10
    Node.js中的进程 在操作系统中,每个应用程序都是一个进程类的实例对象。在Node.js中,使用process对象代表Node.js应用程序。该对象是一个全局对象,可以在REPL...Node.js中的进程对象具有的属性属性值如下。 ex...
  • 到底什么是文件描述符???

    千次阅读 多人点赞 2021-10-28 10:10:51
    文件描述符1、文件描述符的引入1.1 系统调用接口的引入1.2 文件描述符2、文件描述符2.1 演示文件描述符2.2 文件描述符的返回值2.3 文件描述符底层原理(重点)2.3 文件描述符修饰规则3、总结 1、文件描述符的引入 ...
  • 一、系统环境 操作系统:Windows10专业版 64位 Redis版本:redis-64.3.2 二、问题描述 cmd 进入redis 3.2目录 执行 redis-server.exe redis.windows.conf 可以启动redis服务, ...错误1067:进程意外终止。...
  • Init进程在初始化过程中会启动很多重要的守护进程,因此,了解Init进程的启动过程有助于我们更好的理解Android系统。 在介绍Init进程前,我们先简单介绍下Android的启动过程。从系统角度看,Android的启动过程可分为...
  • 依稀记得去年年中时,有个同事也问过我如何获取被调用进程的输出结果,当时还研究了一番,只是没有做整理。今天花点时间,将该方法整理成文。(转载请指明出于breaksoftware的csdn博客)  在信息化非常发达的今天,...
  • init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程),Zygote是所有Java进程的父进程 Framework Zygote进程启动后,加载ZygoteInit类,注册Zygote Socket服务端套接字;加载...
  • 文章目录零、前言一、实验内容二、实验步骤三、实验数据及源代码四、实验结果分析五、思考题1、进程创建与进程并发执行2、进程的睡眠、同步、撤消等进程控制3、多进程通过加锁互斥并发运行4、进程间通过信号机制实现...
  • 深入理解Node.js 进程与线程(8000长文彻底搞懂)

    万次阅读 多人点赞 2019-08-08 07:36:00
    进程与 线程是一个程序员的必知概念,面试经常被问及,但是一些文章内容只是讲讲理论知识,可能一些小伙伴并没有真的理解,在实际开发中应用也比较少。本篇文章除了介绍概念,通过Node.js 的角度讲解 进程与 线程,...
  • 进程 第二天 (fork函数&子进程与父进程&守护进程)

    万次阅读 多人点赞 2018-08-13 20:37:20
    详细标注:进程 第二天 (fork函数&amp;子进程与父进程&amp;守护进程) 一、fork()函数 在Linux系统内,创建子进程的方法是使用系统调用fork()函数。fork()函数是Linux系统内一个非常重要的函数,它与我们...
  • 常见错误

    千次阅读 2021-03-19 13:55:35
    error code(错误代码)=0是操作成功完成。 error code(错误代码)=1是功能错误。 error code(错误代码)=2是系统找不到指定的文件。 error code(错误代码)=3是系统找不到指定的路径。 error code(错误代码...
  • 常见http状态码以及可能的错误分析

    千次阅读 2018-08-19 15:02:03
    其目的是允许服务器接受对某些其他进程的请求(可能是每天只运行一次的面向批处理的进程),而不要求用户代理与服务器的连接一直持续到进程完成为止。使用此响应返回的实体应该包括请求的当前状态的指示,以及指*向...
  • 操作系统 进程描述与控制

    千次阅读 2017-03-19 13:43:00
    本系列是计算机操作系统的笔记 采用的书是《计算机操作系统》汤子瀛第二章 进程描述与控制2.1前驱图和程序执行2.1.1前驱图1. 所谓前驱图,是指一个有向无循环图,可记为DAG(Directed Acyclic Graph),它用于描述...
  • Android service进程保护

    万次阅读 2016-05-11 14:16:23
    什么才叫应用进程保活应用进程保活可以理解为应用位于后台永远不能被杀死。这里的可以简略地分为两种情况,第一种是当系统资源紧俏的时候或者基于某种系统自身的后台运行规则选择杀死你的后台应用来获得更多的资源,...
  • 进程

    万次阅读 2019-03-28 21:04:35
    进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来...
  • Linux编程入门四进程

    千次阅读 2019-06-10 16:26:39
    系统允许一个进程创建新进程(即为子进程),子进程还可以创建新的子进程,形成进程树结构。整个Linux系统的所有进程也是一个树形结构。树根是系统自动构造的,即在内核态下执行的0号进程,它是所有进程的祖先。由0...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 146,231
精华内容 58,492
关键字:

关于进程属性描述错误的是