教材为《操作系统概念》原书第九版,中文版。
3.2 内核采取一些动作以便在两个进程之间进行上下文切换,请描述一下。
答:当进行上下文切换时,内核会将旧进程状态保存在其PCB中,然后加载经调度而要执行的新进程的上下文。内核首先将当前进程的上下文保存在内存中的PCB中, 然后再将下一个进程在内存中的PCB里的上下文读取出来。 上下文包含CPU寄存器里的内容、堆、用户栈、内存管理信息、数据、文本。
3.4 针对UNIX和Linux系统的进程init在进程终止方面的作用,请解释一下。
如果父进程没有调用wait()
就终止,以致于子进程成为孤儿进程 (orphan process),Linux 和 UNIX 对这种情况的处理是:将 init 进程
作为孤儿进程的父进程。(init进程
是UNIX和Linux系统内进程树的根进程。)进程init
定期调用wait()
,以便收集任何孤儿进程的退出状态,并释放孤儿进程标识符和进程表条目。
3.7 采用图3-32所示的程序,确定行A、B、C、D中的pid的值。(假定父进程和子进程的pid分别为2600 和 2603。)
答:
-
pid(A) = 0
-
pid(B) = 2603
-
pid© = 2603
-
pid(D) = 2600
3.10 使用如图3-33所示的程序,请解释一下行X和Y的输出是什么。
答:子程序
是父程序
的副本,改变子程序
不会改变父程序
。
-
行X:CHILD: 0 CHILD: -1 CHILD: -4 CHILD: -9 CHILD: -16
-
行Y:PARENT: 0 PARENT: 1 PARENT: 2 PARENT: 3 PARENT: 4
3.11下面设计的优缺点是什么?系统层次和用户层次都要考虑。
a. 同步和异步通信
b. 自动和显式缓冲
c. 复制传送和引用传送
d. 固定大小和可变大小消息
答:
-
同步和异步通信:
同步通信:
优点:
生产者仅需调用阻塞send()并且等待,直到息被送到接收者或邮箱。同样,当消费者调用receive()时,它会阻塞直到有一个消息可用。
缺点:
同步通信较复杂,双方时钟的允许误差较小,会因为等待反馈信息而一直占用内存和系统资源。
异步通信:
优点:
异步通信简单,双方时钟可允许一定误差。可以使系统尽可能高效率的进行不同的对象进行通信。
缺点:
在发出信息后不能立刻得到结果,甚至可能因为某种错误的发生而不能得到结果。
-
自动和显式缓冲:
自动缓冲:
优点:
有限容量:队列长度为有限的n;因此,最多只能有n个消息驻留其中。如果在发送新消息时队列未满,那么该消息可以放在队列中(或者复制消息或者保存消息的指针),且发送者可以继续执行而不必等待。
无限容量:不管多少消息都可在其中等待,发送者从不阻塞。
缺点:
有限容量:链路容量是有限的。如果链路已满.那么发送者应阻塞,直到队列空间有可用的为止。
显示缓冲:
优点:
占用内存空间小,避免系统资源浪费。
缺点:
可能使用户在发送信息时被阻塞而等待一段时间,直到接收者接收到消息。
-
复制传送和引用传送:
复制传送:
优点:
可以保持通信传输之间的一致性。
缺点:
不能够改变参数的状态可能带来不便。
而引用发送允许改变参数的状态,由此他的优点之一是它允许程序员写一个分布式版本的一个集中的应用程序。 -
固定大小和可变大小消息:
由进程发送的消息可以是定长的或变长的。如果只能发送定长消息,那么系统级的实现十分简单,不过这一限制让编程任务更加困难。相反的,变长消息要求更复杂的系统级实现,但是编程任务变得更简单。
3.12
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main(void)
{
pid_t pid;
pid = fork();
if(pid<0){
perror("fork err!!");
exit(EXIT_FAILURE);
}else if(pid == 0){
printf("this is child , pid = %d\n",getpid());
while(1){
sleep(1000);
}
}else{
printf("this is parent pid is %d,but i don't wait my child %d\n",getpid(),pid);
}
return 0;
}
3.13
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <pthread.h>
#define MIN_PID 300
#define MAX_PID 5000
#define PID_COUNT (MAX_PID - MIN_PID + 1)
typedef struct{
pthread_mutex_t mutex;
unsigned char *pid_map;
} pid_manager;
pid_manager * manager;
int allocate_map(void){
manager = (pid_manager *)malloc(sizeof(pid_manager));
if (manager == NULL){
return -1;
} // Allocation failed
manager->pid_map = (unsigned char *)calloc(PID_COUNT / CHAR_BIT, sizeof(unsigned char));
if (manager->pid_map == NULL){
free(manager);
return -1; // Allocation failed
}
pthread_mutex_init(&(manager->mutex), NULL);
return 1; // Success
}
int allocate_pid(void){
pthread_mutex_lock(&(manager->mutex));
for (int i = 0; i < PID_COUNT; ++i){
int byte_index = i / CHAR_BIT;
int bit_index = i % CHAR_BIT;
if (!(manager->pid_map[byte_index] & (1 << bit_index))){
manager->pid_map[byte_index] |= (1 << bit_index);
pthread_mutex_unlock(&(manager->mutex));
return i + MIN_PID;
}
}
// No available pid
pthread_mutex_unlock(&(manager->mutex));
return -1;
}
void release_pid(int pid){
pthread_mutex_lock(&(manager->mutex));
int index = pid - MIN_PID;
int byte_index = index / CHAR_BIT;
int bit_index = index % CHAR_BIT;
manager->pid_map[byte_index] &= ~(1 << bit_index);
pthread_mutex_unlock(&(manager->mutex));
}
void cleanup(void){
pthread_mutex_destroy(&(manager->mutex));
free(manager->pid_map);
free(manager);
}
int main(void)
{
if (allocate_map() == -1){
printf("Failed to allocate pid map.\n");
return 1;
}
int pid1 = allocate_pid();
int pid2 = allocate_pid();
printf("Allocated PIDs: %d, %d\n", pid1, pid2);
release_pid(pid1);
int pid3 = allocate_pid();
printf("Allocated PID after release: %d\n", pid3);
cleanup();
return 0;
}
3.14
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <limits.h>
//function to generate and print the Collatz sequence
void generateCollatzSequence(int n){
while (n > 1){
printf("%d, ", n);
if (n % 2 == 0){
n = n / 2;
}else{
//handling potential overflow by checking if the next number will exceed INT_MAX
if (n > (INT_MAX - 1) / 3){
printf("Error: Overflow detected.\n");
exit(1);
}n = 3 * n + 1;
}
}
printf("%d\n", n);
}
int main(int argc, char* argv[]){
//check if the correct number of command-line arguments is provided
if (argc != 2) {
printf("Usage: %s <starting_number>\n", argv[0]);
exit(1);
}
pid_t pid;
pid = fork();
if (pid < 0) {
//error handling for fork failure
perror("Fork failed");
exit(1);
}else if (pid == 0){
printf("Child: %d\n", getpid()); //child process
int n = atoi(argv[1]);
generateCollatzSequence(n);
}else{
wait(NULL);
printf("Parent: %d\n", getpid()); //parent process
}
return 0;
}
3.20
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define BUFFER_SIZE 4096
int main(int argc, char* argv[])
{
//check if the correct number of command-line arguments is provided
if (argc != 3) {
printf("Usage: %s <source_file> <destination_file>, like: ./file_copy /mnt/input.txt /mnt/copy.txt\n", argv[0]);
return 1;
}
//open the source file for reading
int source_fd = open(argv[1], O_RDONLY);
if (source_fd == -1) {
perror("Failed to open source file.");
return 1;
}
// Create the destination file or truncate if it already exists
int dest_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (dest_fd == -1) {
perror("Failed to create or open destination file, please ensure that your files are in the folder of the Linux virtual machine.");
close(source_fd);
return 1;
}
//create a buffer for reading from the source file
char buffer[BUFFER_SIZE];
ssize_t bytes_read;
//loop until all data is read from the source file
while ((bytes_read = read(source_fd, buffer, BUFFER_SIZE)) > 0) {
//write the data read from the source file to the destination file
ssize_t bytes_written = write(dest_fd, buffer, bytes_read);
if (bytes_written != bytes_read) {
perror("Failed to write to destination file");
close(source_fd);
close(dest_fd);
return 1;
}
}
//check for read error
if (bytes_read == -1) {
perror("Failed to read from source file");
close(source_fd);
close(dest_fd);
return 1;
}
//close the file descriptors
close(source_fd);
close(dest_fd);
printf("File copied successfully.\n");
return 0;
}