《Operating Systems: Three Easy P

2020-04-01  本文已影响0人  美航球馆

背景

这篇文章是操作系统的第二篇笔记,我们将开始探索 process 具体的 API。因为涉及到具体的 API ,主要的精力应该放在这本书 第二篇 的 Homework,辅之以相关的文档,所以在简单介绍几个重要的 API 之后,我会在最后添上我的 Homework code。

接口列表

我们先依次来看下三个比较重要的 API Family

The fork() System Call

fork() 这个 API 是用来创建一个新的 process,这个新的 process 非常特殊,它特殊在几乎是调用这个接口的 process 的复制者,所以我们也称这个创建出来的 process 为 child process. 这个函数的 文档

/// 所依赖的库
#include <unistd.h>
/// - Parameters:
///    -无
/// - Return Value:
///    - On success, the PID(process ID) of the child process is returned in the parent, 
///    - and 0 is returned in the child.
///    - On failure, -1 is returned in the parent, 
///    - no child process is created, and errno is set appropriately
pid_t fork(void);

我在贴一下书上的例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {
        // fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        // child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
    } else {
        // parent goes down this path (original process)
        printf("hello, I am parent of %d (pid:%d)\n", rc, (int) getpid());
    }
    return 0;
}

在早期的 unix 系统中,创建 process 的函数就这一个,就没在提供其它接口了。这就很令人好奇了,为什么不提供一些类似 createProcess 这样的接口,可以让使用者创建一个全新的 process,而是只能通过复制 process,来创建一个新的 process。

在网上简单搜索了下,大致可以理解为这样的设计可以使得接口变得非常简单。而在 Windows 中,是有这样的函数的 CreateProcess,可以看到所需要的参数非常多,大多数的参数还是结构体,所以还是挺复杂的。这么一对比,fork() 这个接口确实简洁的多(也符合 unix 的设计哲学),可以仔细看看这个高票回答

The Wait() System Call

wait() 这个函数就如同它的名字所揭示的那样,是用来等待 child 的 process 结束的。当 parent process 调用这个函数的时候,它不会继续运行下去而处于 suspend 的状态,直到它的 child process 结束运行时,parent process 才会继续运行下去。这里有一点要注意的是,只有 parent process wait child process 这个函数才会有效,child process wait parent 是无效的,这章 Homework的有道题也说明了这点。

我们同样来看下这个函数的文档 和 书上的代码示例 。

/// 依赖的库
#include <sys/types.h>
#include <sys/wait.h>
/// - Parameters:
///    - a pointer to int which is child process's status
/// - Return Value:
///    - on success, returns the process ID of the terminated child;
///    - on error, -1 is returned 
pid_t wait(int *status);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {
        // fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        // child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
        sleep(1);
    } else {
        // parent goes down this path (original process)
        int wc = wait(NULL);
        printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
           rc, wc, (int) getpid());
    }
    return 0;
}

相似功能的函数还有很多,waitpidwaitid 等等,这些函数没有本质的区别,只是参数略有不同,有兴趣的可以看上面那个文档,也详细的介绍了这些函数,稍后在作业里我们也会用到其中一个函数。

The exec() family System Call

exec() System Call 包含一系列的函数:

it loads code (and static data) from that executable and overwrites its current code segment (and current static data) with it; the heap and stack and other parts of the memory space of the program are re-initialized. Then the OS simply runs that program, passing in any arguments as the argv of that process. Thus, it does not create a new process; rather, it transforms the currently running program into a different running program

书上的例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    int rc = fork();
    if (rc < 0) {
        // fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        // child: redirect standard output to a file
        close(STDOUT_FILENO); 
        open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);

        // now exec "wc"...
        char *myargs[3];
        myargs[0] = strdup("wc");   // program: "wc" (word count)
        myargs[1] = strdup("p4.c"); // argument: file to count (change to your file path)
        myargs[2] = NULL;           // marks end of array
        execvp(myargs[0], myargs);  // runs word count
    } else {
        // parent goes down this path (original process)
        int wc = wait(NULL);
        assert(wc >= 0);
    }
    return 0;
}

Homework

GitHub 地址

上一篇 下一篇

猜你喜欢

热点阅读