1、UNIX 操作系统实验首都师范大学 信息工程学院系统分析与管理实验室12目 录1、UNIX 安装及基本操作 2、UNIX 编程基础.3、UNIX 进程实验.4、UNIX 进程间通信5、UNIX 文件系统实验 6、UNIX 综合实验19223346490实验六 综合实验(多线程与死锁)一、背景知识操作系统中的一个进程在同一时刻只能做一件事情,有了多个控制线程之后,在程序设计时可以把进程设计成在同一时刻能够做不止一件事,每个线程处理各自独立的任务,而且多个线程之间可以实现数据的共享,这种方法有很多好处。但是共享数据必须保持一致性,因此我们通过对互斥量加锁,确保同一时间只有一个线程操作共享数据。这个
2、势必带来一个问题,对互斥量操作不当的话,就会引起死锁。研究死锁的情况,可以让我们在以后的程序中更好地避免死锁问题。在 Linux 环境中,我们通过有目的地设计死锁程序,观察多线程死锁的情况,分析多线程对互斥量操作的要点,从而在以后的程序中尽可能地避免死锁的发生。二、实验内容1、单线程与多线程对互斥量操作如果线程对同一个互斥量加锁两次,那么这个线程自身就会陷入死锁状态。在 Linux 环境下,通过设计两个实验来分析这种情况。单线程程序,main 线程对互斥量进行两次加锁,查看程序运行情况。图 1 两次加锁情况参考程序:-thread1.c-#include #include #include #
3、include struct foo /定义 struct fooint f_count;pthread_mutex_t f_lock;struct foo *fp; /定义全局变量 fpstruct foo * /结构体 fp 初始化foo_alloc(void)1struct foo *fp;if(fp = (foo *)malloc(sizeof(struct foo) != NULL) /初始化 fpfp-f_count = 0;if(pthread_mutex_init(return(NULL);return(fp);int main(void) /main 线程fp = foo_a
4、lloc();printf(“init fp , fp-f_count : %dn“, fp-f_count);/*first lock*/printf(“first lock: “); if(pthread_mutex_lock( /加锁成功,返回值为 0,其它任何情况都表示加锁不成功fp-f_count+; /对结构体 fp 中的值进行修改fp-f_count+;printf(“first lock, fp-f_count : %dn“, fp-f_count);else printf(“lock wrong!n“); /pthread_mutex_unlock( /解除第一次的锁(选择打
5、开) /*lock again*/printf(“second lock: “); /第二次对互斥量进行加锁if(pthread_mutex_lock(fp-f_count+;fp-f_count+; printf(“second lock,fp-f_count : %dn“, fp-f_count);else printf(“lock again wrong!n“); /在 main 线程中只对互斥量进行加锁,未解锁pthread_mutex_destroy( /销毁互斥锁,并释放 fpfree(fp); printf(“main thread exit!n“); /输出 main 线程退出
6、提示exit(0); /main 线程退出-thread1.c-在 Linux 下用 g+(即 C+的编译器)进行编译链接,并调试运行,结果如下:请记录结果:2实验分析(在结果中分析线程可能的状态,必要时修改程序,加入暂停,以便观察):对多线程而言,main 线程和新创建 thread 1,main 线程对互斥量进行两次加锁,而 thread 1 只输出两句话,不对互斥量进行任何操作,查看程序运行情况。图 2 多线程加锁参考程序:-thread2.c-#include #include #include #include 3#include “ourhdr.h“ #include “error
7、.c“ /自定义文件,线程创建不成功时输出出错信息struct foo /结构体 fooint f_count;pthread_mutex_t f_lock;struct foo *fp; /定义全局变量 fpstruct foo *foo_alloc(void)struct foo *fp;if(fp = (foo *)malloc(sizeof(struct foo) != NULL) /初始化分 fpfp-f_count = 0;if(pthread_mutex_init( return(NULL);return(fp);void * thr_fn1(void *) /thread 1p
8、rintf(“now in thread 1n“); printf(“thread 1 exitn“);pthread_exit(void *)1); /thread 1 退出int main(void)int err;pthread_t tid1;void *tret;fp = foo_alloc();printf(“init fp , fp-f_count : %dn“, fp-f_count);err = pthread_create(if(err != 0)err_quit(“cant create thread 1 : %sn“, strerror(err); /在 main 线程里
9、创建 thread1,thr_fn1 是 thread 1 最先执行的函数,当 thr_fn1 函数返回时,thread 1 将退出sleep(2); /mian 线程 sleep 2 秒/*first lock*/printf(“first lock: “); /主线程第一次对互斥量 fp-f_lock 加锁if(pthread_mutex_lock(fp-f_count+;4fp-f_count+;printf(“first lock, fp-f_count : %dn“, fp-f_count); else printf(“first lock wrong!n“);/*lock agai
10、n*/printf(“second lock: n“); /主线程第二次对互斥量 fp-f_lock 加锁if(pthread_mutex_lock(fp-f_count+;fp-f_count+;printf(“second lock, fp-f_count : %dn“, fp-f_count);else printf(“second lock wrong!n“);err = pthread_join(tid1, if(err != 0)err_quit(“cant join with thread 1:%sn“, strerror(err); /main 通过 pthread_join
11、等待 thread 1 退出pthread_mutex_destroy(free(fp); /释放结构体 fpprintf(“main thread exit!n“); /输出 main 线程退出提示exit(0); /main 线程退出-thread2.c-在 Linux 下用 g+(即 C+的编译器)进行编译链接,并调试运行,结果如下:请记录结果:实验分析(在结果中分析线程可能的状态,必要时修改程序,加入暂停,以便观察):5两次实验的比较:实验结论:2、多线程对互斥量的操作在多线程编程中,我们通过对互斥量进行加锁来保持共享数据的一致性,但是对互斥量的操作必须谨慎,操作不当便会产生死锁,下面
12、四个实验是分析产生死锁的情况以及如何避免死锁。main 线程创建 3 个线程,thread 1,thread 2,thread 3,thread 1 对互斥量进行加锁,但不解锁,thread 2 也对互斥量进行加锁,thread 3 销毁锁状态。图 3 多线程加锁流程6图 4 加锁示意图参考代码:-pthread1.c-#include #include #include #include #include “ourhdr.h“#include “error.c“struct foo /定义结构体int f_count;pthread_mutex_t f_lock;struct foo *fp
13、; /定义全局变量 fpstruct foo *foo_alloc(void)struct foo *fp;if(fp = (foo *)malloc(sizeof(struct foo) != NULL) /初始化 fpfp-f_count = 0;if(pthread_mutex_init(return(NULL);/ printf(“fp-f_count : %dn“, fp-f_count);return(fp);void * thr_fn1(void *) /thread 1 printf(“now in thread 1n“); /*lock*/7if(pthread_mutex_
14、lock(fp-f_count+; /改变变量 fp-f_count 的值fp-f_count+;else printf(“lock wrong!n“);printf(“thread 1 fp-f_count : %dn“, fp-f_count);sleep(60);printf(“thread 1 sleep overn“);/*unlock*/ if(pthread_mutex_unlock(/ else printf(“unlock wrong!n“); pthread_exit(void *)1); /thread 1 退出,未对互斥量解锁void * thr_fn2(void *)
15、 /thread 2sleep(20);printf(“now in thread 2n“); /*lock,will happen dead lock*/if(pthread_mutex_lock(fp-f_count+; /加锁成功,则改变变量的值 fp-f_count+;printf(“thread 2 fp-f_count : %dn“, fp-f_count);if(pthread_mutex_unlock( /对互斥量解锁else printf(“thread 2 cant lock!n“);pthread_exit(void *)2); /thread 2 退出void * th
16、r_fn3(void *) /thread 3sleep(60);printf(“now in thread 3n“); /*destory lock*/if(pthread_mutex_destroy(free(fp); /释放 fpelse printf(“cant destory lock!n“); /printf(“thread 3 fp-f_count after destory : %dn“, fp-f_count);pthread_exit(void *)3); /thread 3 退出int main(void)8int err;pthread_t tid1, tid2, ti
17、d3;void *tret;fp = foo_alloc(); /初始化 fpprintf(“init fp , fp-f_count : %dn“, fp-f_count);err = pthread_create( /创建 thread 1if(err != 0)err_quit(“cant create thread 1 : %sn“, strerror(err); /创建不成功 ,做相应的处理err = pthread_create( /创建 thread 2if(err != 0)err_quit(“cant create thread 2 : %sn“, strerror(err)
18、;err = pthread_create( /创建 thread 3if(err != 0)err_quit(“cant create thread 3 : %sn“, strerror(err);err = pthread_join(tid1, /main 等待 thread 1 返回if(err != 0)err_quit(“cant join with thread 1:%sn“, strerror(err);printf(“thread 1 exit code %dn“, (int)tret); /输出 thread 1 的退出状态值 err= pthread_join(tid2,
19、/main 等待 thread 2 返回if(err!=0)err_quit(“cant join with thread 2:%sn“, strerror(err);printf(“thread 2 exit code %dn“, (int)tret);err= pthread_join(tid3, /main 等待 thread 3 返回if(err!=0)err_quit(“cant join with thread 3:%sn“, strerror(err);printf(“thread 3 exit code %dn“, (int)tret); free(fp); /释放 fpexi
20、t(0); /main 线程退出-pthread1.c-程序输出结果:9实验分析(在结果中分析线程可能的状态,必要时修改程序,加入暂停,以便观察):若 main 线程创建 2 个线程,thread 1,thread 2,thread 1 对互斥量进行加锁,sleep 一段时间后解锁,thread 2 也对互斥量进行加锁。图 5 程序结构图图 6 程序示意图参考代码:-pthread2.c-#include #include #include #include 10#include “ourhdr.h“#include “error.c“struct foo /定义结构体int f_count;
21、pthread_mutex_t f_lock;struct foo *fp;struct foo *foo_alloc(void)struct foo *fp;if(fp = (foo *)malloc(sizeof(struct foo) != NULL) fp-f_count = 0;if(pthread_mutex_init(return(NULL);return(fp);void * thr_fn1(void *) /thread 1printf(“now in thread 1n“); /*lock*/if(pthread_mutex_lock(fp-f_count+; /改变变量的
22、值fp-f_count+;printf(“thread 1 fp-f_count : %dn“, fp-f_count);sleep(8); /thread 1 sleep 8 秒printf(“thread 1 sleep overn“); /*unlock*/if(pthread_mutex_unlock(else printf(“unlock wrong!n“);else printf(“lock wrong!n“);pthread_exit(void *)1); /thread 1 退出void * thr_fn2(void *) sleep(2);printf(“now in thr
23、ead 2n“);/*trylock,no dead lock*/11if(pthread_mutex_lock(fp-f_count+;fp-f_count+;printf(“thread 2 fp-f_count : %dn“, fp-f_count);sleep(5);if(pthread_mutex_unlock(else printf(“thread 2 unlock wrong!n“);else printf(“thread 2 cant lock!n“);pthread_exit(void *)2); /thread 2 退出int main(void)int err;pthre
24、ad_t tid1, tid2, tid3;void *tret;fp = foo_alloc();printf(“init fp , fp-f_count : %dn“, fp-f_count);err = pthread_create( /创建 thread 1if(err != 0)err_quit(“cant create thread 1 : %sn“, strerror(err);err = pthread_create( /创建 thread 2if(err != 0)err_quit(“cant create thread 2 : %sn“, strerror(err); er
25、r = pthread_join(tid1, /main 等待 thread 1 返回if(err != 0)err_quit(“cant join with thread 1:%sn“, strerror(err);printf(“thread 1 exit code %dn“, (int)tret);err= pthread_join(tid2, /main 等待 thread 2 返回if(err!=0)err_quit(“cant join with thread 2:%sn“, strerror(err);printf(“thread 2 exit code %dn“, (int)t
26、ret); exit(0); /main 线程退出-pthread2.c-程序输出结果:12实验分析(在结果中分析线程可能的状态,必要时修改程序,加入暂停,以便观察):若 main 线程创建了 3 个线程:thread 1,thread 2,thread 3,thread 1 对互斥量加锁,但始终不解锁,thread 2 在 thread 1 未解锁的情况下用 trylock 尝试对互斥量加锁,thread 3 销毁互斥锁状态,此时的程序为:图 7 程序结构13图 8 程序示意图参考代码:-pthread3.c-#include #include #include #include #incl
27、ude “ourhdr.h“#include “error.c“struct foo int f_count;pthread_mutex_t f_lock;struct foo *fp;struct foo *foo_alloc(void)struct foo *fp;if(fp = (foo *)malloc(sizeof(struct foo) != NULL) fp-f_count = 0;if(pthread_mutex_init(return(NULL);return(fp);void * thr_fn1(void *) /thread 1printf(“now in thread
28、1n“); /*lock*/if(pthread_mutex_lock(fp-f_count+;fp-f_count+;else printf(“lock wrong!n“);printf(“thread 1 fp-f_count : %dn“, fp-f_count); sleep(20);printf(“thread 1 sleep overn“); pthread_exit(void *)1); /thread 1 退出,未解锁void * thr_fn2(void *) /thread 2sleep(10);printf(“now in thread 2n“); /*trylock,n
29、o dead lock*/if(pthread_mutex_trylock(fp-f_count+; fp-f_count+; printf(“thread 2 fp-f_count : %dn“, fp-f_count);if(pthread_mutex_unlock( /加锁的情况下对互斥量解锁else printf(“thread 2 unlock wrong!n“);else printf(“thread 2 cant lock!n“);sleep(15);pthread_exit(void *)2); /thread 2 退出 void * thr_fn3(void *) /thre
30、ad 3sleep(30);printf(“now in thread 3n“);/*destory lock*/if(pthread_mutex_destroy(free(fp);else printf(“cant destory lock!n“); / printf(“thread 3 fp-f_count after destory : %dn“, fp-f_count); pthread_exit(void *)3); /thread 3 退出int main(void)int err;pthread_t tid1, tid2, tid3;15void *tret;fp = foo_a
31、lloc();printf(“init fp , fp-f_count : %dn“, fp-f_count);err = pthread_create( /创建 thread 1if(err != 0)err_quit(“cant create thread 1 : %sn“, strerror(err);err = pthread_create( /创建 thread 2if(err != 0)err_quit(“cant create thread 2 : %sn“, strerror(err);err = pthread_create( /创建 thread 3if(err != 0)
32、err_quit(“cant create thread 3 : %sn“, strerror(err);err = pthread_join(tid1, /等待 thread 1 退出if(err != 0)err_quit(“cant join with thread 1:%sn“, strerror(err);printf(“thread 1 exit code %dn“, (int)tret);err= pthread_join(tid2, /等待 thread 2 退出if(err!=0)err_quit(“cant join with thread 2:%sn“, strerror
33、(err);printf(“thread 2 exit code %dn“, (int)tret);err= pthread_join(tid3, /等待 thread 3 退出if(err!=0)err_quit(“cant join with thread 3:%sn“, strerror(err);printf(“thread 3 exit code %dn“, (int)tret);free(fp); exit(0); /main 线程退出-pthread3.c-程序输出结果:16实验分析(在结果中分析线程可能的状态,必要时修改程序,加入暂停,以便观察):若 main 线程创建 4 个
34、线程,thread 1,thread 2,thread 3,在 thread 1 退出后,重新创建thread 1。thread 1 对互斥量进行加锁,但不解锁,thread 2 也对互斥量进行加锁,thread 3 销毁锁状态。图 9 流程图图 10 示意图17参考代码:-pthread4.c-#include #include #include #include #include “ourhdr.h“#include “error.c“struct foo int f_count;pthread_mutex_t f_lock;struct foo *fp;struct foo *foo_a
35、lloc(void)struct foo *fp;if(fp = (foo *)malloc(sizeof(struct foo) != NULL) fp-f_count = 0;if(pthread_mutex_init(return(NULL);return(fp);void * thr_fn1(void *) /thread 1printf(“now in thread 1n“);/*lock*/if(pthread_mutex_lock(fp-f_count+;fp-f_count+;else printf(“lock wrong!n“);printf(“thread 1 fp-f_c
36、ount : %dn“, fp-f_count);sleep(30);printf(“thread 1 sleep overn“);pthread_exit(void *)1); /thread 1 退出void * thr_fn2(void *) 18sleep(10);printf(“now in thread 2n“);/*lock,will happen dead lock*/if(pthread_mutex_lock(fp-f_count+;fp-f_count+; printf(“thread 2 fp-f_count : %dn“, fp-f_count);if(pthread_
37、mutex_unlock( else printf(“thread 2 unlock wrong!n“);else printf(“thread 2 cant lock!n“); pthread_exit(void *)2);void * thr_fn3(void *) /thread 3sleep(50);printf(“now in thread 3n“); /*destory lock*/if(pthread_mutex_destroy(free(fp);else printf(“cant destory lock!n“);pthread_exit(void *)3); /thread
38、3 退出 int main(void)int err;pthread_t tid1, tid2, tid3;void *tret;fp = foo_alloc();printf(“init fp , fp-f_count : %dn“, fp-f_count);err = pthread_create( /创建 thread 1if(err != 0)err_quit(“cant create thread 1 : %sn“, strerror(err);err = pthread_create( /创建 thread 2if(err != 0)err_quit(“cant create th
39、read 2 : %sn“, strerror(err);err = pthread_create( /创建 thread 3if(err != 0)err_quit(“cant create thread 3 : %sn“, strerror(err); err = pthread_join(tid1, /main 等待 thread 1 返回19if(err != 0)err_quit(“cant join with thread 1:%sn“, strerror(err);printf(“thread 1 exit code %dn“, (int)tret); sleep(10); er
40、r = pthread_create( /重新创建 thread 1if(err != 0)err_quit(“cant create thread 1 : %sn“, strerror(err);err= pthread_join(tid2, /main 等待 thread 2 返回 if(err!=0)err_quit(“cant join with thread 2:%sn“, strerror(err);printf(“thread 2 exit code %dn“, (int)tret);err= pthread_join(tid3, /main 等待 thread 3 返回if(err!=0)err_quit(“cant join with thread 3:%sn“, strerror(err);printf(“thread 3 exit code %dn“, (int)tret);err= pthread_join(tid1, /main 等待新创建的 thread 1 返回if(err!=0)err_quit(“cant join with thread 1 again:%sn“, strerror(err);printf(“thread 1 exit code %dn“, (int)tret);free(fp); exit(0); /main 线程退出-