西安邮电大学操作系统进程实验报告含源码.docx
《西安邮电大学操作系统进程实验报告含源码.docx》由会员分享,可在线阅读,更多相关《西安邮电大学操作系统进程实验报告含源码.docx(13页珍藏版)》请在冰豆网上搜索。
![西安邮电大学操作系统进程实验报告含源码.docx](https://file1.bdocx.com/fileroot1/2023-1/23/1b414072-ce39-4d9e-9ba2-2ddb633a2cf0/1b414072-ce39-4d9e-9ba2-2ddb633a2cf01.gif)
西安邮电大学操作系统进程实验报告含源码
西安邮电大学
(计算机学院)
课内实验报告
实验名称:
进程管理
专业名称:
软件工程
班级:
学生姓名:
学号(8位):
*******
实验日期:
2014年11月4日
一.实验目的及实验环境
(一)、实验环境
1.硬件
(1)主机:
PentiumIII以上;
(2)内存:
128MB以上;
(3)显示器:
VGA或更高;
(4)硬盘空间:
至少100MB以上剩余空间。
2.软件
Ubuntu下gcc编译器、gdb调试工具。
(二)、实验目的
进程:
1、通过观察、分析实验现象,深入理解多进程并发执行的过程、fork函数在创建子进程时对内存的操作;2、加深对进程概念的理解,明确进程和程序的区别;3、进一步认识并发执行的实质;4、分析进程争用资源的现象,学习解决进程互斥的方;5、了解Linux系统中进程通信的基本原理。
线程:
1、理解多线程的概念,学会Linux编程中的线程的创建与终止。
2、理解多线程并发工作时对资源的抢占,通过本实验掌握在Linux操作系统中遵循Posix线程标准接口进行多线程程序编程,熟练掌握线程的创建pthread_create()。
互斥与死锁:
1、理解死锁的产生原因与Linux编程中对临界资源进行加锁使得多进程或多线程对临界资源进行互斥访问。
2、利用信号量或者互斥锁实现线程间的同步。
二、实验内容
<1>、完成程序填空
<2>、回答下列问题
进程:
1、你最初认为运行结果会怎么样?
答:
会持续输出0-9号进程,直到输入数字键+回车,则会杀死该进程,接下来的输出将不会有该进程号,当输入q+回车,则退出程序。
2、实际的结果什么样?
有什么特点?
试对产生该现象的原因进行分析。
答:
实际的结果与预期差不多。
因输入进程总数3小于设定的最大进程数,因此按进程数3来处理。
随机输出0-2号进程,sleep(SLEEP_INTERVAL),循环输出,输入数字键,则会杀死该数字对应的进程,直到输入q退出循环,然后kill杀死本组所有进程。
分析:
每创建一个子进程时,将其pid存储在pid[i]中,i存储在proc_number,然后调用死循环函数do_something(),输出该进程的代号proc_number;当输入数字键时,主进程会执行kill(pid[ch-'0'],SIGTERM),从而杀死(ch-‘0’)号进程。
当输入q时循环退出,kill(0,SIGTERM),杀死本组所有进程,程序退出。
3、proc_number这个全局变量在各个子进程里的值相同吗?
为什么?
答:
相同,因为子进程相互独立,资源互不影响。
4、kill命令在程序中使用了几次?
每次的作用是什么?
执行后的现象是什么?
答:
kill命令在程序中使用了2次:
kill(pid[ch-'0'],SIGTERM)和kill(0,SIGTERM);
第一次是杀死该进程号pid[ch-‘0’],执行后接下来的结果中不会有该进程号,就会使该子进程真正结束。
第二次是杀死本组所有进程。
即主进程以及它创建的所有子进程。
执行后程序退出,进程结束。
5、使用kill命令可以在进程的外部杀死进程。
进程怎样能主动退出?
这两种退出方式哪种更好一些?
答:
进程在main函数中return,或调用exit()函数都可以正常退出。
而使用kill命令则是异常退出。
当然是正常退出比较好,若在子进程退出前使用kill命令杀死其父进程,则系统会让init进程接管子进程。
当用kill命令使得子进程先于父进程退出时,而父进程又没有调用wait函数等待子进程结束,子进程处于僵死状态,并且会一直保持下去,直到系统重启。
子进程处于僵死状态时,内核只保存该进程的必要信息以被父进程所需,此时子进程始终占着资源,同时减少了系统可以创建的最大进程数。
6.在do_something()输出pro_number的地址,把do_something里的死循环改成10次,问实际创建的子进程个数有什么变化?
答:
pro_number的地址不变,当把死循环改成10次后,子进程个数只有10个,并且杀死后的进程还是会重新输出。
线程:
1、你最初认为前三列数会相等吗?
最后一列斜杠两边的数字是相等,还是大于或者小于关系?
答:
我认为前三列数不会相等,因为线程之间在抢占cpu资源,三个线程运行次数是随机的,最后一列的数字左边等于右边。
2、最后的结果如你所料吗?
有什么特点?
试对原因进行分析。
答:
最后的结果不是我所预料的,最后斜杠两边的数字时一样的,原因在与我在程序中添加了信号量。
3、thread的CPU占用率是多少?
为什么会这样?
答:
在我的电脑上cpu占用率147%,一个方面是线程执行的都是无限循环的代码,另一方面是线程之间抢占资源很激烈。
4、thread_worker()内是死循环,它是怎么退出的?
你认为这样退出好吗?
答:
thread_worker()函数内是死循环,退出时因为主函数中设置的输入q时循环退出。
整个进程的终止导致了所有线程的结束,这样结束线程不好,因为如果线程使用临界资源的时候没有释放就结束了,那么这个临界资源就会被认为是被已经退出的线程占用着,从而得不到释放。
互斥与死锁:
1、你预想deadlock.c的运行结果会如何?
答:
运行结果可能会发生中止现象,我认为thread1和thread2会相互争抢资源,有一定的概率发生死锁,因为他们的运行顺序是抢占式的。
2、deadlock.c的实际运行结果如何?
多次运行每次的现象都一样吗?
为什么会这样?
答:
实际的运行结果是:
开始几次运行正常,但是经过多次的运行之后,其中一次会让程序卡死,无法再执行。
这是因为thread1锁定了资源1,thread2锁定了资源2,两个线程又同时需要对方的资源,这样导致了死锁。
三.方案设计
进程:
利用fork()函数创建进程,并将每个进程的进程号保存在主进程中保存进程号的数组。
每个进程输出自己是第几个进程与自己的进程号。
当用户输入’q’时,主进程向每个进程发送终止信号,杀死所有进程;学习fork与kill的用法,补全程序代码,调试运行,观察并 分析实验结果。
线程:
主进程创建三个线程并发工作。
这三个线程都对main_counter进程修改(没执行一次循环将main_counter加1),也将属于自己线程的变量counter[i]加1,最后比较三个线程counter值之和与main_counter的大小。
补全程序代码,调试运行,观察并 分析实验结果。
互斥与死锁:
准备好上节实验3完成的程序。
阅读参考资料,了解互斥锁的加锁机制 及相关的系统调用。
找到实验3程序的代码临界区,用临界区解决 main_counter 与sum 不同步的问题。
对main_counter与sum加锁实现三个线程的互斥访问。
四.测试数据及运行结果
进程:
线程:
互斥与死锁:
五.总结
在本次实验中,我学会了创建进程和杀死进程,创建线程和杀死线程,线程的种类,和线程创建及管理机制并且了解了线程互斥锁的类型。
重新理解了互斥与同步的概念以及死锁及其相关内容。
更进一步认识死锁的发生条件和预防死锁发生的方法。
死锁发生的条件有互斥条件,占有且等待条件,不可抢占条件等。
我们只要破坏死锁发生条件之一我们就可以预防死锁的发生!
本实验采用破坏占有且等待条件预防死锁发生!
处理及调度的算法有一定的难度,因为其理论上的难度,但是通过学习让我对其有了更加深入的了解,让我认识到了,操作系统是一项真正实用,而且很有意义的学科,增加了我对操作系统的兴趣,也为以后的学习打下理论基础。
六、源代码
线程:
#include
#include
#include
#include
#include
#defineMAX_CHILD_NUMBER10
#defineSLEEP_INTERVAL2
intproc_number=0;
voiddo_something();
main(intargc,char*argv[])
{
intchild_proc_number=MAX_CHILD_NUMBER;
inti;
charch;
pid_tchild_pid;
pid_tpid[10]={0};/*存放每个子进程的id*/
if(argc>1)
{
child_proc_number=atoi(argv[1]);
child_proc_number=(child_proc_number>10)?
10:
child_proc_number;
}
for(i=0;i{
child_pid=fork();
if(child_pid==-1)
{
perror("fork");
}
elseif(child_pid==0)
{
proc_number=i;
do_something();
}
else
pid[i]=child_pid;
}
/*用户选择杀死进程,数字表示杀死该进程,q表示退出*/
printf("请输入要杀死进程的编号(q退出):
\n");
while((ch=getchar())!
='q')
{
if(isdigit(ch))
{
kill(pid[ch-'0'],SIGTERM);
}
}
/*杀死本组的所有进程*/
for(i=0;i<=proc_number;i++)
{
kill(pid[i],SIGTERM);
}
kill(0,SIGTERM);
return;
}
voiddo_something()
{
for(;;)
{
printf("ThisisprocessNo.%danditspidis%d\n",proc_number,getpid());
sleep(SLEEP_INTERVAL);
}
}
线程:
#include
#include
#include
#include
#include
#include
#defineMAX_THREAD3/*线程的个数*/
unsignedlonglongmain_counter,counter[MAX_THREAD];
/*unsignedlonglong是比long还长的整数*/
sem_tS1,S2;
void*thread_worker(void*);
void*thread_worker(void*p){
intthread_num;
thread_num=(int)p;
for(;;){
sem_wait(&S1);
sem_wait(&S2);
counter[thread_num]++;/*本线程的counter加一*/
main_counter++;/*主counter加一*/
sem_post(&S2);
sem_post(&S1);
}
}
intmain(intargc,char*argv[])
{
inti,rtn,ch;
pthread_tpthread_id[MAX_THREAD]={0};
sem_init(&S1,0,1);
sem_init(&S2,0,1);
for(i=0;i{
rtn=pthread_create(&pthread_id[i],NULL,thread_worker,(void*)i);
}
do
{
unsignedlonglongsum=0;
sem_wait(&S1);
sem_wait(&S2);
for(i=0;isum+=counter[i];
printf("第%d个counter的值是%llu\n",i+1,counter[i]);
}
printf("main_counter的值:
%llusum的值%llu\n",main_counter,sum);
sem_post(&S2);
sem_post(&S1);
}while((ch=getchar())!
='q');
return0;
}
互斥锁:
#include
#include
#include
#include
#include
#defineLOOP_TIMES10000
pthread_mutex_tmutex1=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_tmutex2=PTHREAD_MUTEX_INITIALIZER;
void*thread_worker(void*);
voidcritical_section(intthread_num,inti);
void*thread_worker(void*p)
{
inti;
for(i=0;i{
//对互斥锁上锁
pthread_mutex_lock(&mutex1);
pthread_mutex_lock(&mutex2);
critical_section(2,i);
//对互斥锁解锁
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
}
voidcritical_section(intthread_num,inti)
{
printf("Thread%d:
%d\n",thread_num,i);
}
intmain()
{
intrtn,i;
pthread_tpthread_id=0;
rtn=pthread_create(&pthread_id,NULL,thread_worker,NULL);
if(rtn!
=0)
{
printf("pthread_createERROR!
\n");
return-1;
}
for(i=0;i{
pthread_mutex_lock(&mutex1);
pthread_mutex_lock(&mutex2);
critical_section(1,i);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
//互斥锁销毁
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return0;
}
信号量:
#include
#include
#include
#include
#include
#include
#defineLOOP_TIMES10000
sem_tS1,S2;
void*thread_worker(void*);
voidcritical_section(intthread_num,inti);
void*thread_worker(void*p)
{
inti;
for(i=0;i{
//信号量减一
sem_wait(&S2);
sem_wait(&S1);
critical_section(2,i);
//信号量加一
sem_post(&S1);
sem_post(&S2);
}
}
voidcritical_section(intthread_num,inti)
{
printf("Thread%d:
%d\n",thread_num,i);
}
intmain()
{
intrtn,i;
sem_init(&S1,0,1);
sem_init(&S2,0,1);
pthread_tpthread_id=0;
rtn=pthread_create(&pthread_id,NULL,thread_worker,NULL);
if(rtn!
=0)
{
printf("pthread_createERROR!
\n");
return-1;
}
for(i=0;i{
sem_wait(&S1);
sem_wait(&S2);
critical_section(1,i);
sem_post(&S1);
sem_post(&S2);
}
//销毁信号量
sem_destroy(&S1);
sem_destroy(&S2);
return0;
}