西安郵電學院
Linux实验报告
题 目1: 进程
题 目2: 线程
题 目3: 互斥
实验1进程
1.1 实验目的
通过观察、分析实验现象,深入理解进程及进程在调度执行和内存空间等方面的特点,
掌握在POSIX 规范中fork和kill系统调用的功能和使用。
1.2 实验要求
1.2.1 实验环境要求
1. 硬件
(1) 主机:Pentium III 以上;
(2) 内存:128MB 以上;
(3) 显示器:VGA 或更高;
(4) 硬盘空间:至少100MB 以上剩余空间。
2. 软件
Linux 操作系统,内核2.4.26 以上,预装有X-Window 、vi、gcc、gdb 和任
意web 浏览器。
1.2.2 学生实验前的准备工作
学习man 命令的用法,通过它查看fork 和kill 系统调用的在线帮助,并阅读参
考资料,学会fork 与kill 的用法。
复习C 语言的相关内容。
1.3 实验内容
1.先猜想一下这个程序的运行结果。假如运行“./process 20”,输出会是什么样?
执行./process20会输出10个进程交替执行。输入要删除的进程编号,回车则删除该进程,输入q,回车删除进程组,程序结束。
2.然后按照注释里的要求把代码补充完整,运行程序。可以多运行一会儿,并在
此期间启动、关闭一些其它进程,看process 的输出结果有什么特点,记录下这个结果。
3.开另一个终端窗口,运行“ps aux|grep process”命令,看看process 究竟启动了多少个进程。回到程序执行窗口,按“数字键+回车”尝试杀掉一两个进程,再到另一个窗口看进程状况。
执行./forkTest 10 输入命令 ps aux|grep ./forkTest 后显示有12个进程在运行(10个子进程,1个父进程,最后一个为ps aux|grep ./forkTest命令的进程号 ),删除1号进程后,再输入ps aux|grep ./forkTest命令,则显示的进程数为11.
按q 退出程序再看进程情况。
1.4 回答下列问题。
1. 你最初认为运行结果会怎么样?
进程交替执行,当输入某进程编号加回车后该进程会被杀死,不再输出,当输入q加回车后剩余的所有子进程都被杀死,程序运行结束。
2. 实际的结果什么样?有什么特点?试对产生该现象的原因进行分析。
结果与上述的预期相同。
特点:各进程交替执行。无确定顺序。
分析:当程序执行到for(i = 0; i < child_proc_number; i++)循环后,调用fork()函数创建第一个子进程,然后父进程与该子进程交替执行,当子进程抢到cpu时继续往下执行if(child_pid == 0)语句中的程序段,若在执行到do_something();语句时,则调用该函数,执行死循环for(;;)输出该进程的相关内容,并在输出语句后加上sleep(SLEEP_INTERVAL);语句,给其他进程抢占cpu的机会。这个过程不一定可以连续的执行下去,因为在该过程中,父进程随时可能抢到cpu,再次执行fork();创建另一个子进程或者执行else语句(由其上次执行到的位置决定)。该子进程的执行与第一个子进程类似。自此该3个进程交替执行,当父进程执行fork()时,则继续创建新的子进程以此类推。直到父进程完成for(i = 0; i < child_proc_number; i++)循环,child_proc_number个子进程创建完成。此时child_proc_number个子进程加一个父进程一起交替性运行,当父进程再次抢到cpu时,则执行while((ch = getchar()) != 'q')循环时,则按用户的输入杀死相应的进程。用户输入q时,则杀死子进程组,while((ch = getchar()) != 'q')循环结束,当执行return 0;语句后该父进程也结束,整个程序结束。
3. proc_number 这个全局变量在各个子进程里的值相同吗?为什么?
不相同。
因为子进程会把父进程的所有资源复制一份。而父进程在创建一个新的子进程时的i值都不同,当新创建子进程执行时,将i赋值给该子进程的变量proc_number。
4. kill 命令在程序中使用了几次?每次的作用是什么?执行后的现象是什么?
当输入要删除的进程编号时会调用一次kill,最后输入q结束时会调用一次kill。
输入要删除的进程编号后,执行的结果为:输出除过已被删掉的进程的其余进程信息。
输入q则显示“已终止”,整个程序执行结束。
5. 使用kill 命令可以在进程的外部杀死进程。进程怎样能主动退出?这两种退
出方式哪种更好一些?
进程自己调用exit()或程序执行完后return().
进程自己调用exit()结束的方式会比较好。
6.补充后的程序源代码。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <ctype.h>
#define MAX_CHILD_NUMBER 10
#define SLEEP_INTERVAL 2
int proc_number = 0;
void do_something();
int main(int argc, char *argv[])
{
int child_proc_number = MAX_CHILD_NUMBER;
int i;
char 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 > 10) ? 10:child_proc_number;
}
for(i = 0; i < child_proc_number; i++)
{
child_pid = fork();
if(child_pid == 0)
{
proc_number = i;
pid[i] = getpid();
do_something();
}
else if(child_pid < 0)
{
perror("fork error!\n");
}
else
{
pid[i] = child_pid;
}
}
while((ch = getchar()) != 'q')
{
if(isdigit(ch))
{
if(pid[ch - '0'] != -1)
{
kill(pid[ch-'0'],SIGTERM);
pid[ch-'0'] = -1;
}
}
}
kill(0,SIGTERM);
return 0;
}
void do_something()
{
for(;;)
{
printf("This prcess is NO.%*d\n",proc_number+3,proc_number);
sleep(SLEEP_INTERVAL);
}
}
实验2线程
2.1 实验目的
通过观察、分析实验现象,深入理解线程及线程在调度执行和内存空间等方面的特点,并掌握线程与进程的区别。掌握在POSIX 规范中pthread_create() 函数的功能和使用方法
2.2 实验要求
2.2.1 实验环境要求
1. 硬件
(1) 主机:Pentium III 以上;
(2) 内存:128MB 以上;
(3) 显示器:VGA 或更高;
(4) 硬盘空间:至少100MB 以上剩余空间。
2. 软件
Linux 操作系统,内核2.4.26 以上,预装有X-Window 、vi、gcc、gdb 和任
意web 浏览器。
2.2.2 学生实验前的准备工作
阅读参考资料,了解线程的创建等相关系统调用。
2.3 实验内容
按照注释里的要求把代码补充完整,正确编译程序后,先预计一下这个程序的运行结果。具体的结果会是什么样?运行程序。开另一个终端窗口,运行“ps aux”命令,看看thread 的运行情况,注意查看thread 的CPU 占用率,并记录下这个结果。
预计输出的前三列数不相等,main_counter的值与sum的值相等,且为前三列显示的线程运行次数之和。
运行ps aux命令后,./thread的CPU占用率为197
2.4 实验中的问题
1. 你最初认为前三列数会相等吗?最后一列斜杠两边的数字是相等,还是大于或者
小于关系?
不会相等,因为三个进程交替执行,每个进程运行的时间及次数都不确定。
main_count的值应该等于sum的值等于3个线程执行次数的总和。
2. 最后的结果如你所料吗?有什么特点?试对原因进行分析。
不,前3列的输出结果与预期结果相同,但main_count的值大于sum的值。
分析:因为main_counter属于临界资源,可能会出现当一个线程正在执行main_counter++时,另一个线程也要执行main_counter++的情况,这样就会使main_counter的值不准确。又线程运行顺序的不确定性(交替性),可能在一个线程执行了main_counter++后,还未执行counter[thread_num]++时,CPU便被主线程抢去,执行for(i = 0; i < MAX_THREAD; i++)循环,使sum += counter[i];此时sum的值便比main_counter的值小了。再输出个各线程巡行的次数,及main_counter和sum的值,结果与预期的理论值不符。
3. thread 的CPU 占用率是多少?为什么会这样?
197。因为三个线程调用的函数执行的是一个死循环for(;;),使得CPU的利用率过高。
4. thread_worker()内是死循环,它是怎么退出的?你认为这样退出好吗?
输入q回车,主线程会退出while循环,执行return()函数,结束整个程序。自然子线程也都被迫终止,死循环也就退出了!这样的退出不好。
5. 补充及修改后的程序源代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#define MAX_THREAD 3
unsigned long long main_counter, counter[MAX_THREAD]; //unsigned long long 鏄瘮long杩橀暱鐨勬暣褰?€?
void* thread_worker(void *);
int main(int argc, char *argv[])
{
int i,ch;
int num[3];
pthread_t thid,pthread_id[MAX_THREAD] = {0};
for(i = 0; i < MAX_THREAD; i++)
{
num[i] = i;
if(pthread_create(&thid,NULL,(void*)thread_worker,&num[i]) == 0)
{
pthread_id[i] = thid;
//thread_worker(&i);
}
else
{
printf("thread creater failed!\n");
// exit(1);
}
}
do
{
unsigned long long sum = 0;
/*姹傛墍鏈夌嚎绋媍ounter鐨勫拰*/
for(i = 0; i < MAX_THREAD; i++)
{
sum += counter[i];
printf("%d %llu ",i,counter[i]);
}
printf("\n\n%llu\n%llu\n\n",main_counter,sum);
}while((ch = getchar()) != 'q');
return 0;
}
void* thread_worker(void* p)
{
int thread_num;
thread_num = *((int*)p);
for(;;)
{
main_counter++;
counter[thread_num]++;
sleep(1);
}
return NULL;
}
实验3互斥
3.1 实验目的
通过观察、分析实验现象,深入理解理解互斥锁的原理及特点
掌握在POSIX 规范中的互斥函数的功能及使用方法
3.2 实验要求
3.2.1 实验环境要求
1. 硬件
(1) 主机:Pentium III 以上;
(2) 内存:128MB 以上;
(3) 显示器:VGA 或更高;
(4) 硬盘空间:至少100MB 以上剩余空间。
2. 软件
Linux 操作系统,内核2.4.26 以上,预装有X-Window 、vi、gcc、gdb 和任意web 浏览器。
3.2.2 学生实验前的准备工作
准备好上节实验完成的程序thread.c 。
阅读参考资料,了解互斥锁的加解锁机制及相关的系统调用。
4.3 实验内容
1.找到thread.c 的代码临界区,用临界区解决main_counter 与sum 不同步的问题。
在使用到main_counter与sum临界资源的临界区上加上p,v操作。
修改后的thread.c的代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#define MAX_THREAD 3
unsigned long long main_counter, counter[MAX_THREAD]; //unsigned long long 鏄瘮long杩橀暱鐨勬暣褰?€?pthread_mutex_t mutext=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void* thread_worker(void *);
int main(int argc, char *argv[])
{
int i,ch;
int num[3];
pthread_t thid,pthread_id[MAX_THREAD] = {0};
for(i = 0; i < MAX_THREAD; i++)
{
num[i] = i;
if(pthread_create(&thid,NULL,(void*)thread_worker,&num[i]) == 0)
{
pthread_id[i] = thid;
}
else
{
printf("thread creater failed!\n");
// exit(1);
}
}
pthread_mutex_lock(&mutex);
do
{
unsigned long long sum = 0;
/*姹傛墍鏈夌嚎绋媍ounter鐨勫拰*/
for(i = 0; i < MAX_THREAD; i++)
{
sum += counter[i];
printf("%d %llu ",i,counter[i]);
}
printf("\n\n%llu\n%llu\n\n",main_counter,sum);
}while((ch = getchar()) != 'q');
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutext);
return 0;
}
void* thread_worker(void* p)
{
int thread_num;
thread_num = *((int*)p);
for(;;)
{
pthread_mutex_lock(&mutext);
main_counter++;
counter[thread_num]++;
sleep(1);
pthread_mutex_unlock(&mutext);
}
return NULL;
}
仔细阅读程序,编译程序后,先预计一下这个程序的运行结果。
运行程序。若程序没有响应,按ctrl+c 中断程序运行,然后再重新运行,如此
反复若干次,记录下每次的运行结果。
若产生了死锁,请修改程序,使其不会死锁。
4.4 实验中的问题
1. 你预想deadlock.c 的运行结果会如何?
线程1 ,2会交替运行,且执行到一半会终止。
2. deadlock.c 的实际运行结果如何?多次运行每次的现象都一样吗?为什么会这样?
交替执行!每次执行到一半都会终止。
每次运行的结果不同。
线程终止是因为,线程的推进顺序不合法。如果在线程1执行pthread_mutex_lock(&mutex1);语句,申请1号资源成功后,线程2又执行pthread_mutex_lock(&mutex2);语句,申请2号资源成功。当线程1想要申请2号资源,即执行pthread_mutex_lock(&mutex2);语句或线程2想要申请1号资源,即执行pthread_mutex_lock(&mutex1);时,这两个线程将陷入无限的等待状态而产生死锁。
为避免死锁的产生,则应调换线程1或线程2对1,2号资源加锁的顺序。即使线程1,2对1,2号资源的加锁顺序一致。即一次性为其分配了它所需要的所有资源,避免了死锁的产生。
3.修改前补充的程序源代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#define LOOP_TIMES 10000
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
void* thread_worker(void*);
void critical_section(int thread_num,int i);
int main(void)
{
int rtn,i;
pthread_t pthread_id = 0;
rtn = pthread_create(&pthread_id,NULL,thread_worker,NULL);
if(rtn != 0)
{
printf("pthread_create ERROR!\n");
return -1;
}
for(i = 0; i < LOOP_TIMES; 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);
return 0;
}
void* thread_worker(void* p)
{
int i;
for(i = 0; i < LOOP_TIMES; i++)
{
pthread_mutex_lock(&mutex2);
pthread_mutex_lock(&mutex1);
critical_section(2,i);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
}
void critical_section(int thread_num,int i)
{
printf("Thread%d:%d\n",thread_num,i);
}
4.修改后补充的程序源代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#define LOOP_TIMES 10000
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
void* thread_worker(void*);
void critical_section(int thread_num,int i);
int main(void)
{
int rtn,i;
pthread_t pthread_id = 0;
rtn = pthread_create(&pthread_id,NULL,thread_worker,NULL);
if(rtn != 0)
{
printf("pthread_create ERROR!\n");
return -1;
}
for(i = 0; i < LOOP_TIMES; i++)
{
pthread_mutex_lock(&mutex1);
pthread_mutex_lock(&mutex2);
critical_section(1,i);
// sleep(1);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
void* thread_worker(void* p)
{
int i;
for(i = 0; i < LOOP_TIMES; i++)
{
pthread_mutex_lock(&mutex1);
pthread_mutex_lock(&mutex2);
critical_section(2,i);
// sleep(1);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
}
void critical_section(int thread_num,int i)
{
printf("Thread%d:%d\n",thread_num,i);
// sleep(1);
}
实验二Linux常用命令使用一、实验目的1.掌握Linux一般命令格式。2.掌握有关文件和目录操作的常用命令。3.掌握有关进程操作…
Linux操作系统实验报告实验编号实验编号实验名称实验名称实验1Linux安装实验2掌握虚拟机的使用实验目的1熟练掌握Linux系…
实验项目名称Linux基础操作实验项目编号一学号组号上机实践日期20xx919上机实践时间2学时一目的本次实验所涉及并要求掌握的知…
专业计算机科学与技术学号姓名Linux操作系统报告单名称系统常用命令任课教师专业计算机科学与技术班级姓名学号完成日期成绩12345…
实验一Linux的基本操作命令一实验目的了解Linux的基本命令实现Linux的文件系统操作二实验内容1在Linux字符环境下练习…
Linux考试实验1修改运行级别,级别切换:(1)vi/etc/inittab将5改为3(2)reboot2修改root密码:进入…
280行修改为DocumentRoot“/var/www/html/myweb”[root@localhostbbc]#httpd…
实验八Linux的系统及网络管理实验班级:k1273-5姓名:李远琳学号:20xx9730516上机时间:20xx年x月x日任课教…
LINUX实验报告专业班级学号姓名实验一实验名称Linux基本命令的使用实验时间2学时实验目的熟练使用Linux字符界面窗口系统的…
河南师范大学综合性、设计性实验项目简介学院名称(公章):软件学院学年20##-20##第1学期填表日期:20##年12月11_日注…
实验项目名称Linux基础操作实验项目编号一学号组号上机实践日期20xx919上机实践时间2学时一目的本次实验所涉及并要求掌握的知…