进程API
- 编写一个调用 fork() 的程序。在调用 fork() 之前,让主进程访问一个变量(如 x)并将其值设为某个值(如 100)。子进程中的变量值是多少?当子进程和父进程都改变 x 的值时,变量会发生什么变化?
调用fork会创建一个与父进程几乎完全一样的副本,且会复制当前执行的上下文,所以子进程中的变量值是100,它们改变x的值都是互不影响的。执行
python q1.py
可得到结果如下:1 2 3 4
Parent process - x: 100 Parent process - x after modification: 150 Child process - x: 100 Child process - x after modification: 50
- 编写一个程序,打开一个文件(使用 open() 系统调用),然后调用 fork() 创建一个新进程。子进程和父进程都能访问 open() 返回的文件描述符吗?当它们同时(即同时)向文件写入时会发生什么情况?
父进程的文件描述符也会继承,所以子进程也可以往
test.txt
写入消息,虽然父进程和子进程的文件描述符是相同的,但是它们各自的文件描述符指向的是相同文件的不同偏移位置。在写入文件时,操作系统会维护两个进程的文件偏移,确保它们互不干扰。执行python q2.py
可验证。 - 使用fork()编写另一个程序。子进程应打印“hello”,父进程应打印“goodbye”。您应尽量确保子进程始终先打印;您能在不在父进程中调用wait()的情况下实现吗?
如果不使用wait,则可以使用
time.sleep()
通过短暂的休眠来实现。执行python q3.py
可验证结果。 - 编写一个调用fork()然后调用某种形式的exec()来运行程序/bin/ls的程序。看看你能否尝试所有的exec()变体,包括(在Linux上)execl()、execle()、execlp()、execv()、execvp()和execvpe(). 为什么你认为同一基本调用有这么多变体?
q4.py
尝试了所有的变体。这些变体的存在主要是为了提供不同的参数传递方式和环境设置,以满足不同的编程需求和场景。具体如下:- execl()和execlp():
- execl()接受一个可变数量的参数,用于指定执行文件的路径以及命令行参数,参数列表以NULL结尾。
- execlp()函数接受与execl()相同的参数列表,但它还会在系统的PATH环境变量中搜索可执行文件。
- execv()和execvp():
- execv()接受两个参数,第一个参数是要执行的文件的路径,第二个参数是一个字符串数组,表示命令行参数,数组的第一个元素通常是执行文件的名称。
- execvp()函数与execv()类似,但它会在系统的PATH环境变量中搜索可执行文件。
- execle()和execvpe():
- execle()函数允许指定新程序的环境变量,它接受一个额外的参数environ,用于传递环境变量数组。
- execvpe()函数允许指定新程序的环境变量,并且会在系统的PATH环境变量中搜索可执行文件。
- execl()和execlp():
- 现在编写一个程序,在父进程中使用wait()等待子进程完成。wait()返回什么?如果在子进程中使用wait()会发生什么?
wait()返回的状态信息通常是一个16位的整数,其中高8位存储了子进程的退出状态码,低8位存储了终止信号的编号(如果子进程是由信号终止的话)。如果在子进程中调用wait()函数,由于子进程没有子进程,wait()函数会立即返回-1,并设置 errno 为 ECHILD。实验见
q5.py
- 对之前的程序稍作修改,这次使用 waitpid() 而不是 wait()。 waitpid() 什么时候有用?
当您想要等待特定子进程完成而不是像 wait() 那样等待任何子进程完成时,waitpid() 非常有用。它允许您指定您有兴趣等待的子进程的 PID。这在父进程生成多个子进程并需要单独处理它们的情况下非常有用。
- 编写一个程序,创建一个子进程,然后在子进程中关闭标准输出(STDOUT FILENO)。如果子进程在关闭描述符后调用 printf() 来打印一些输出,会发生什么?
如果我们关闭 stdout 文件描述符,我们将无法使用 printf() 在屏幕上写入内容。但不会发生任何错误。
- 编写一个程序,创建两个子进程,并使用pipe()系统调用将一个子进程的标准输出连接到另一个子进程的标准输入。
我们使用 pipe() 系统调用创建一个管道,如果不成功则退出。我们通过 fork() 调用创建第一个子进程(我们称之为 A),然后,在为父进程运行的代码部分中,我们进行第二个 fork() 调用来创建第二个子进程(我们称之为 B)。 A 使用 dup2 使 stdout 指向管道的写入端,并向管道的写入端传递一个字符串。B使用dup2使stdin指向管道的读取端,并从管道的读取端读取。这将 A 的标准输出连接到 B 的标准输入。