操作系统实验报告_进程部分
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
西安邮电学院
操作系统实验报告
专业名称:软件工程班级:软件0701 学号:04075021 学生姓名:孟阿龙
实验1 掌握Linux基本命令和开发环境
1.掌握常用的Linux shell命令;
掌握linux下的基本命令的用法。
ls,cat,mkdir,rm,touch,less,cp,mv,head,tail,sort,echo
2. 掌握编辑环境VIM;
学习vim的基本使用。
i,a:进入编辑模式
v:进入可视模式
esc;进入命令模式
编辑模式下可以和正常的文本输入方式一样。
V进入可视模式可以使用y进行复制,d进行剪切,p进行粘贴。
esc进入命令模式可以w进行文件存盘,q退出vim,q!不保存而退出,u撤销。
3. 掌握编译环境gcc及跟踪调试工具gdb
gcc编译文件的格式
gcc -o 目标文件源文件
gcc 源文件
gcc -g -o 目标文件源文件
gdb基本调试命令:
l:列出当前文件
b linenumber,在指定的行设置断点
Info br 查看断点信息
Info source 查看源码信息
Info stack 查看堆栈信息
Info args 查看当前的参数
List function 列出某个函数
disable/enable 使断点失效或有效
delete 删除断点
step 单步执行命令
print a :打印出变量a的内容
实验二进程
一实验目的:
通过观察分析实验现象,深入理解进程及进程在调度执行和内存空间等方面的特点,掌握fork和kill系统调用的功能和使用。
二实验前准备:
学习man 命令的用法,通过它查看fork 和kill 系统调用的在线帮助,并阅读参考资料学会fork 与kill 的用法。
复习C 语言的相关内容。
三实验内容:
按照所给的残缺版代码读懂程序,然后回答问题。
(残缺版实验代码略)
1.先猜想一下这个程序的运行结果。
假如运行“./process 20”,输出会是什么样?
将会产生10个进程。
因为程序设定最大产生进程数为10。
2.然后按照注释里的要求把代码补充完整,运行程序。
可以多运行一会儿,并在
此期间启动、关闭一些其它进程,看process 的输出结果有什么特点,记录下这个结果。
开另一个终端窗口,运行“ps aux|grep process”命令,看看process 究竟启动了多少个进程。
回到程序执行窗口,按“数字键+回车”尝试杀掉一两个进程,再到另一个窗口看进程状况。
如果执行./process 20
打开另一个终端用ps aux | grep process可以看到有11个名称为process的进程
运行。
这是有一个主进程,在主进程中产生了10个子进程。
所以共有11个名称为process 的进程在运行。
在程序执行窗口按下数字键+回车这是会杀死对应的进程。
切换到另一个终端下查看可以看到刚才杀死的进程在他的后面会出现<defunt>标志。
表示该进程已经被杀死了。
3.按q 退出程序再看进程情况。
按下q之后所有名称为process的进程都被杀死了。
这是由于按下q之后主进程调用kill(0,SIGTERM)向所有同组的进程发出了终止信号。
所以所有名称为process的进程都被杀死了。
实验报告问题:
1.你最初认为运行结果会怎么样?
最初认为程序执行后会根据所给的参数产生相应数量的同名进程。
按下数字+回车会杀死相应的进程。
按下q会杀死所的进程。
2. 实际的结果什么样?有什么特点?试对产生该现象的原因进行分析。
实际结果和我预期的是相同的。
产生的子进程数最多是10个,这是因为我在程序中设定了产生进程的最大数为10。
当所提供的数字小于10时则准确产生相应数量的子进程。
当所给的参数大于10时就只产生10个进程。
这在程序中是由我下面的语句控制的。
if(argc > 1) {
child_proc_number = atoi(argv[1]);
child_proc_number=(child_proc_number>MAX_CHILD_NUM)?10:child_proc_number;
}
3. proc_number 这个全局变量在各个子进程里的值相同吗?为什么?
不相同。
proc_number是每个进程的编号,从0到MAX_CHILD_NUM。
4. kill 命令在程序中使用了几次?每次的作用是什么?执行后的现象是什么?
kill命令使用了两次。
第一次是在while循环中进行的,此时传递给他的第一个参数是一个子进程的id,这时他杀死的是对应的子进程。
第二次是在用户按下q之后调用,此时传递给他的第一个参数是0,表示要杀死对应进程组中的所有进程
5. 使用kill 命令可以在进程的外部杀死进程。
进程怎样能主动退出?这两种退出方式哪种更好一些?
进程退出是当进程执行完自己的do_something()函数之后,最终会调用return语句退出。
或者是当主进程执行到return语句时子进程也就相应的退出了。
这两种方法第二中更好一些,这样子进程可以正常的退出程序不会产生意外。
6. 把你的程序源代码附到实验报告后。
代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <signal.h>
#include <stdlib.h>
#define MAX_CHILD_NUM 10
#define SLEEP_INTERV AL 2
int proc_num = 0;
void do_something();
int main(int argc, char * argv[])
{
int child_proc_number = MAX_CHILD_NUM;
int i = MAX_CHILD_NUM + 1, ch;
pid_t child_pid; /*记录子进程的进程号*/
pid_t pid[10] = {0};
if(argc > 1) {
child_proc_number = atoi(argv[1]);
child_proc_number = (child_proc_number > MAX_CHILD_NUM)?10:child_proc_number;
}
i = 0;
for( ; i < child_proc_number; i++ ) {
child_pid = fork();
proc_num = i;
if(child_pid == 0 ) {
do_something();
} else if (child_pid > 0) {
pid[i] = child_pid;
}
}
printf("input the number you want to kill:");
while ((ch = getchar()) != 'q' ) {
if(isdigit(ch)) {
ch = (int)ch - 48;
if(kill(pid[ch], SIGKILL) < 0) {
perror("kill");
exit(1);
} else {
printf("process %d has been killed!\n\n", pid[ch]);
}
} else {
printf("is not digit\n");
}
getchar();
printf("input the number you want to kill:");
}
kill(0, SIGTERM);
return 0;
}
void do_something()
{
printf("This is process NO%d, and its pid is:%d\n", proc_num, getpid());
for(;;) {
sleep(SLEEP_INTERV AL);
}
}
实验三线程
一实验目的:
通过观察、分析实验现象,深入理解线程及线程在调度执行和内存空间等方面的特点,并掌握线程与进程的区别。
掌握POSIX 规范中pthread_create() 函数的功能和使用方法。
二实验前准备:
阅读参考资料,了解线程的创建等相关系统调用。
三实验过程:
按照注释里的要求把代码补充完整,正确编译程序后,先预计一下这个程序的运行结果。
具体的结果会是什么样?运行程序。
开另一个终端窗口,运行“ps aux”命令,看看thread 的运行情况,注意查看thread 的CPU 占用率,并记录下这个结果。
extern int pthread_create ((pthread_t *__thread,
__const pthread_attr_t *__attr,
void *(*__start_routine) (void *),
void *__arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。
四实验报告问题:
回答下列问题
1.你最初认为前三列数会相等吗?最后一列斜杠两边的数字是相等,还是大于或者小于关
系?
最初我认为前三列数字是不相等,最后一列斜杠两边的数字是相等的。
显然我最初的预料是有问题的。
2. 最后的结果如你所料吗?有什么特点?对原因进行分析。
真实的结果和我的预料是不相同的。
前三列的数字是不相等的。
而且最后一列斜杠两边的数字也是不相等的。
maincounter的值大于sum的值。
具体原因如下:
前三列数是不会相等的,因为每个线程运行的时机是不相同的。
当我们每次按下回车之后每个线程运行他自己的for循环的次数是不相同的。
最后一列斜杠两边的数字是不相等的。
因为每次我们敲击回车时有可能某个子进程正在执行counter[threadnum]++这条语句,当我们敲下回车时这条语句下边的语句
main_counter++非常有可能不能执行到。
而且线程之间进行切换时也有可能是在这种情况下进行的,在加上在主函数中的do-while循环也可能被中断,中断之后每次sum的值就会清零,这就导致了main_counter的值大于sum的值。
要想让斜杠两边的数字相等那就要在程序中加锁解决了。
具体实现见我下面的代码。
3. thread 的CPU 占用率是多少?为什么会这样?
cpu的利用率是100%,这是因为程序中有三个线程而且每个线程都在死循环的进行加法运算。
4. thread_worker()内是死循环,它是怎么退出的?你认为这样退出好吗?
thread_worker()的死循环退出是在主进程被我们强制终止时退出的。
这样退出不好。
应该在适当的时机通过发信号的方式让线程退出程序。
5. 把你的程序源代码附到实验报告后。
并请保留源代码,下次实验需要使用。
源代码;(这是通过加锁解决了斜杠两边数字不相等的问题)
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int myglobal;
pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_function(void *arg)
{
int i, j;
for (i = 0; i < 20; i++) {
pthread_mutex_lock(&mymutex);
j = myglobal;
j = j + 1;
printf(".");
fflush(stdout);
sleep(1);
myglobal = j;
pthread_mutex_unlock(&mymutex);
}
return NULL;
}
int main(void)
{
pthread_t mythread;
int i;
if (pthread_create(&mythread, NULL, thread_function, NULL)) { printf("error creating thread.");
abort();
}
for (i = 0; i < 20; i++) {
pthread_mutex_lock(&mymutex);
myglobal = myglobal + 1;
pthread_mutex_unlock(&mymutex);
printf("o");
fflush(stdout);
sleep(1);
}
if (pthread_join(mythread, NULL)) {
printf("error joining thread.");
abort();
}
printf("\nmyglobal equals %d\n", myglobal);
exit(0);
}
实验四互斥
一实验目的:
通过观察、分析实验现象,深入理解理解互斥锁的原理及特点掌握在POSIX 规范中的互斥函数的功能及使用方法。
二实验前准备:
准备好上节实验完成的程序thread.c 。
阅读参考资料,了解互斥锁的加解锁机制及相关的系统调用。
实验内容
找到thread.c 的代码临界区,用临界区解决main_counter 与sum 不同步的问题。
三实验过程:
仔细阅读程序,编译程序后,先预计一下这个程序的运行结果。
运行程序。
若程序没有响应,按ctrl+c 中断程序运行,然后再重新运行,如此反复若干次,记录下每次的运行结果。
若产生了死锁,请修改程序,使其不会死锁。
四实验问题:
回答下列问题,写入实验报告。
1.你预想deadlock.c 的运行结果会如何?
预想中deadlock大多说情况下是不能运行完成的。
2. deadlock.c 的实际运行结果如何?多次运行每次的现象都一样吗?为什么会这样?
实际运行结果是大多数情况下不能正常执行完成的。
而且每次运行结果是不一样的。
出现这种原因的问题是因为程序中两个线程对临界区加锁了,但是加锁的顺序不对出现了死锁现象。
3. 把修改后的两个程序的源代码附在实验报告后。
修改后的程序:
thread.c
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int myglobal;
pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_function(void *arg)
{
int i, j;
for (i = 0; i < 20; i++) {
pthread_mutex_lock(&mymutex);
j = myglobal;
j = j + 1;
printf(".");
fflush(stdout);
sleep(1);
myglobal = j;
pthread_mutex_unlock(&mymutex);
}
return NULL;
}
int main(void)
{
pthread_t mythread;
int i;
if (pthread_create(&mythread, NULL, thread_function, NULL)) { printf("error creating thread.");
abort();
}
for (i = 0; i < 20; i++) {
pthread_mutex_lock(&mymutex);
myglobal = myglobal + 1;
pthread_mutex_unlock(&mymutex);
printf("o");
fflush(stdout);
sleep(1);
}
if (pthread_join(mythread, NULL)) {
printf("error joining thread.");
abort();
}
printf("\nmyglobal equals %d\n", myglobal);
exit(0);
}
deadlock.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#define LOOP_TIMES 10000
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
void *thread_work(void *p);
void critical_section(int thread_num, int i);
int main(void)
{
int rtn, i;
pthread_t pthread_id; /*存放子线程的id*/
rtn = pthread_create(&pthread_id, NULL, thread_work, NULL);
if( rtn != 0 ) {
printf("pthread_create error!\n");
return -1;
}
/*注意这里加锁的顺序,和threadwork中的加锁顺序,这两种顺序有可能造成死锁*/ for( i=0; i<LOOP_TIMES; i++ ) {
pthread_mutex_lock(&mutex2);
pthread_mutex_lock(&mutex1);
critical_section(1, i);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
void *thread_work(void *p)。