📖 操作系统课程作业

🧪 实验一源代码

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

#define MAX_INPUT 1024
#define MAX_ARGS 10

int main(void) {
char input[MAX_INPUT];
char *args[MAX_ARGS];
pid_t pid;
int status;

while(1) {
printf("myshell20232316dl> ");
if (fgets(input, MAX_INPUT, stdin) == NULL) {
break; // 处理EOF (Ctrl+D)
}

// 去除换行符
input[strcspn(input, "\n")] = '\0';

// 处理exit命令
if(strcmp(input, "exit") == 0) {
break;
}

// 跳过空输入
if(strlen(input) == 0) {
continue;
}

// 分割输入为命令和参数
char *token;
int i = 0;

token = strtok(input, " ");
while(token != NULL && i < MAX_ARGS - 1) {
args[i++] = token;
token = strtok(NULL, " ");
}
args[i] = NULL;

// 创建子进程执行命令
pid = fork();

if(pid < 0) {
perror("fork failed");
continue;
} else if(pid == 0) {
// 子进程执行命令
execvp(args[0], args);

// 如果execvp返回,说明执行失败
perror("execvp failed");
exit(EXIT_FAILURE);
} else {
// 父进程等待子进程结束
waitpid(pid, &status, 0);

if(WIFEXITED(status)) {
printf("Child exited with status %d\n", WEXITSTATUS(status));
}
}
}

return EXIT_SUCCESS;
}

🌟作业二源代码

任务一:多线程运行结果记录与分析

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

void* thread_func(void* arg) {
long id = (long)arg;
for (int i = 0; i < 5; i++) {
printf("线程 %ld 正在运行第 %d 次,线程ID = %lu\n", id, i, pthread_self());
usleep(100000); // 微秒级休眠,制造时间片切换
}
return NULL;
}

int main() {
printf("作业二第一部分:\n");
printf("主线程开始创建子线程...\n");

pthread_t tid[3];
for (long i = 0; i < 3; i++) {
pthread_create(&tid[i], NULL, thread_func, (void*)i);
}

for (int i = 0; i < 3; i++) pthread_join(tid[i], NULL);

printf("所有线程执行完毕。\n");
return 0;
}

任务二:进程地址空间分析

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

// 全局变量和函数用于标识不同区段
int global_var = 10; // 数据段
const int const_global = 100; // 只读数据段
void code_func() {} // 代码段

void* show_addr(void* arg) {
int thread_id = *(int*)arg;
int local_var = 20; // 栈
int* heap_var = malloc(sizeof(int)); // 堆
*heap_var = 30;

printf("\n===== 线程 %d 的地址空间分布 =====\n", thread_id);
printf("代码段地址(函数 code_func) :%p\n", (void*)code_func);
printf("只读数据段地址(const_global):%p\n", (void*)&const_global);
printf("数据段地址(global_var) :%p\n", (void*)&global_var);
printf("堆区地址(malloc 分配) :%p\n", (void*)heap_var);
printf("栈区地址(local_var) :%p\n", (void*)&local_var);

// 展示堆区共享验证(修改堆区数据)
*heap_var += thread_id;
printf("线程 %d 修改堆区数据后值为:%d\n", thread_id, *heap_var);

// 稍作等待以便输出交错显示
usleep(100000);
free(heap_var);
return NULL;
}

int main() {
printf("作业二第二部分:进程地址空间布局分析\n");
printf("主线程开始创建两个子线程...\n");

pthread_t tid1, tid2;
int id1 = 1, id2 = 2;

pthread_create(&tid1, NULL, show_addr, &id1);
pthread_create(&tid2, NULL, show_addr, &id2);

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

printf("\n所有线程执行完毕。\n");
return 0;
}

任务三:堆栈内容展示与分析

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

// 子线程函数:分析堆栈空间布局与增长方向
void *thread_function(void *arg) {
int thread_id = *(int*)arg;
int stack_var1, stack_var2; // 栈变量
int *heap_var1 = malloc(sizeof(int)); // 堆变量1
int *heap_var2 = malloc(sizeof(int)); // 堆变量2

printf("\n===== 线程 %d 堆栈分析 =====\n", thread_id);

// 栈分析
printf("【栈分析】\n");
printf("栈变量 1 地址: %p\n", (void*)&stack_var1);
printf("栈变量 2 地址: %p\n", (void*)&stack_var2);
if (&stack_var1 > &stack_var2)
printf("→ 栈空间向低地址方向增长\n");
else
printf("→ 栈空间向高地址方向增长(非典型情况)\n");

// 堆分析
printf("【堆分析】\n");
printf("堆变量 1 地址: %p\n", (void*)heap_var1);
printf("堆变量 2 地址: %p\n", (void*)heap_var2);
if (heap_var1 < heap_var2)
printf("→ 堆空间向高地址方向增长\n");
else
printf("→ 堆空间向低地址方向增长(非典型情况)\n");

// 比较堆栈的相对位置
printf("【总体比较】\n");
if ((void*)&stack_var1 > (void*)heap_var1)
printf("→ 栈区地址高于堆区地址(符合一般内存分布规律)\n");
else
printf("→ 栈区与堆区分布异常,需注意系统实现差异\n");

free(heap_var1);
free(heap_var2);
return NULL;
}

int main() {
printf("作业二第三部分:堆栈内容展示与分析\n");

int main_stack1, main_stack2; // 主线程栈变量
int *main_heap1 = malloc(sizeof(int)); // 主线程堆变量1
int *main_heap2 = malloc(sizeof(int)); // 主线程堆变量2

printf("\n===== 主线程堆栈分析 =====\n");

// 栈分析
printf("【栈分析】\n");
printf("栈变量 1 地址: %p\n", (void*)&main_stack1);
printf("栈变量 2 地址: %p\n", (void*)&main_stack2);
if (&main_stack1 > &main_stack2)
printf("→ 栈空间向低地址方向增长\n");

// 堆分析
printf("【堆分析】\n");
printf("堆变量 1 地址: %p\n", (void*)main_heap1);
printf("堆变量 2 地址: %p\n", (void*)main_heap2);
if (main_heap1 < main_heap2)
printf("→ 堆空间向高地址方向增长\n");

// 对比堆栈总体位置
printf("【总体比较】\n");
if ((void*)&main_stack1 > (void*)main_heap1)
printf("→ 栈区地址高于堆区地址(符合一般规律)\n");

// 创建两个线程对比堆栈空间
pthread_t thread1, thread2;
int id1 = 1, id2 = 2;

pthread_create(&thread1, NULL, thread_function, &id1);
pthread_create(&thread2, NULL, thread_function, &id2);

pthread_join(thread1, NULL);
pthread_join(thread2, NULL);

free(main_heap1);
free(main_heap2);

printf("\n所有线程堆栈分析完毕。\n");
return 0;
}

任务四:多线程修改共享变量结果展示与分析

(通过多次运行该程序,还会得到不同的最终结果,进一步验证了线程调度的随机性和操作结果的不确定性。)

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

int shared_value = 0; // 共享变量

// 线程1:增加共享变量
void *thread_add(void *arg) {
for (int i = 0; i < 5; i++) {
int temp = shared_value; // 读取共享变量
usleep(rand() % 2000); // 随机延迟,增加调度随机性
temp = temp + 1; // 执行加操作
usleep(rand() % 2000);
shared_value = temp; // 写回共享变量
printf("线程1(+1) 第%d次操作后: shared_value = %d\n", i + 1, shared_value);
}
return NULL;
}

// 线程2:减少共享变量
void *thread_sub(void *arg) {
for (int i = 0; i < 5; i++) {
int temp = shared_value; // 读取共享变量
usleep(rand() % 2000); // 随机延迟,增加调度随机性
temp = temp - 1; // 执行减操作
usleep(rand() % 2000);
shared_value = temp; // 写回共享变量
printf("线程2(-1) 第%d次操作后: shared_value = %d\n", i + 1, shared_value);
}
return NULL;
}

int main() {
printf("作业二第四部分:多线程共享变量与调度随机性分析\n");

pthread_t t1, t2;
srand((unsigned)time(NULL)); // 初始化随机数种子

printf("初始值: shared_value = %d\n", shared_value);

// 创建两个线程:一个加,一个减
pthread_create(&t1, NULL, thread_add, NULL);
pthread_create(&t2, NULL, thread_sub, NULL);

// 等待两个线程执行完毕
pthread_join(t1, NULL);
pthread_join(t2, NULL);

printf("\n所有操作结束。\n");
printf("最终值: shared_value = %d (理论期望值: 0)\n", shared_value);
printf("说明:由于线程交替运行的随机性,结果可能与期望不同。\n");

return 0;
}