《厦门理工学院操作系统实验(共12页).docx》由会员分享,可在线阅读,更多相关《厦门理工学院操作系统实验(共12页).docx(12页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上操作系统实验报告实验序号:4 实验项目名称:线程创建和数据传递学号姓名ZRZ专业、班18计卓1班实验地点指导教师李远敏实验时间2020.4.24一、实验目的及要求1.加深对线程概念的理解,明确进程和线程的区别。2.进一步认识线程并发执行的实质。3.学会利用pthread库,进行线程创建和线程间数据传递二、实验设备(环境)及要求1.Ubuntu操作系统环境2.搭建Ubuntu操作系统下的C语言编程环境。三、实验内容与步骤1.线程的创建:(1)编程实现在主进程中通过线程创建pthread_create()函数来创建新的线程。(2)在主线程和子线程中要通过getpid()及
2、pthread _self()获取对应的进程号和线程号并打印输出2.线程间参数传递:(1)阅读下面主线程与子线程间传参数(多个参数值)的程序代码并输入调试并输出结果; (2) 按下面要求编写子线程间参数传递程序a.程序功能:实现在两个子线程通过全局变量传递数据:即在一个子线程中对全局变量的成员进行赋值,在另一个子线程中对全局变量的成员进行取值并显示b.编程要求:首先要定义一个全局结构类型和对应的变量,定义两个Pthread_t类型变量来保存两个子线程的id;要定义一个主函数和两个用于创建子线程的对应函数在主函数中创建两个函数对应的子线程并对创建是否成功进行判断,创建成功后,等待显示子线程结束进
3、程才结束。在赋值子线程对应函数内要打印进入该子进程的特殊信息,分别对全局变量中相应成员赋值。在显示子线程对应函数内要先等待赋值子线程运行完该线程才开始,打印进入该子进程的特殊信息,并取出全局变量中每个成员的值并显示。3.接收子线程的返回值:(1)阅读下面接收创建子线程的返回值-简单值的程序代码并输入调试并输出结果;针对下列问题进行说明或修改:a.程序运行结果ret= 是一个不确定的值,试说明原因b.将程序中int a=20语句调换到红颜色位置,结果如何c. 将程序中int a=20 int*p=&a;语句置换成蓝颜色语句,结果又如何?(2)阅读下面接收创建子线程返回一个复杂的数据结构变量程序代
4、码并输入、调试、输出结果;针对下列问题进行说明或修改:将temp定义和赋值变为create()函数内定义的局部变量,应如何修改程序对结果又什么影响并说明原因?四、实验结果与数据处理1.线程的创建(1)实验结果:图1:进程的创建一代码图2:程序运行结果(2)结果分析:运行结果:我们可以看到主线程会先打印出相应的ID,然后再是子线程打印自己的ID原因:当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。每个进程至少都有一个主线程
5、,所以没有干预的情况下,主线程都是优先于子线程运行的。 所以在输出ID的时候,主线程会比子线程早输出自己的ID。(3)思考:a.通过以上实验线程执行与函数调用的不同,线程与进程的不同答:线程是程序执行部分,是操作系统的划分。函数是编程中的概念,是功能模块的划分。 b.如何控制主线程与子线程的执行顺序答:我们可以使用sleep函数来对线程进行挂起的操作,从而来控制主线程与子线程的执行顺序。图3:修改后的代码图4:修改后的代码运行结果总结:线程被创建后,并不能保证那个线程先执行,新创建的线程和调用线程的执行顺序不确定,由操作系统进行调度,注意:编译时要连接库libpthread;就是编译的时候要加
6、 -lpthread在C程序中,main(int argc, char *argv)就是一个主线程。我们可以在主线程中做任何普通线程可以做的事情,但它和一般的线程有有一个很大的区别:主线程返回或者运行结束时会导致进程的结束,而进程的结束会导致进程中所有线程的结束。为了不让主线程结束所有的线程,可以用sleep函数挂起线程2.线程间参数传递(1)实验结果:1.输入示例代码调试并输出结果图5:线程间参数传递代码图6:程序运行结果2. 按下面要求编写子线程间参数传递程序a.程序功能:实现在两个子线程通过全局变量传递数据:即在一个子线程中对全局变量的成员进行赋值,在另一个子线程中对全局变量的成员进行取
7、值并显示b.编程要求:首先要定义一个全局结构类型和对应的变量,定义两个Pthread_t类型变量来保存两个子线程的id;要定义一个主函数和两个用于创建子线程的对应函数在主函数中创建两个函数对应的子线程并对创建是否成功进行判断,创建成功后,等待显示子线程结束进程才结束。在赋值子线程对应函数内要打印进入该子进程的特殊信息,分别对全局变量中相应成员赋值。在显示子线程对应函数内要先等待赋值子线程运行完该线程才开始,打印进入该子进程的特殊信息,并取出全局变量中每个成员的值并显示。 图7:线程间参数传递新代码图8:程序运行结果3.接收子线程的返回值(1)实验结果: 图9:返回简单数据类型程序代码图10:返
8、回简单数据类型程序运行结果图11:返回复杂数据类型程序代码图12:返回复杂数据类型程序运行结果(2) 结果分析:a. 程序运行结果ret= 是一个不确定的值,试说明原因答:因为我们在子线程调用的函数中运用了int a=20; int *p=&a的办法,这样会导致ret的值不确定,因为这时候的p是一个局部变量,当函数执行完毕后就会被释放掉,而释放掉以后就会造成指针悬挂的问题,致使ret的值不确定,造成内存泄漏。所以我们要针对这点的话,就要采用全局变量的方法或者是动态释放内存的方法来解决。b. 将程序中int a=20语句调换到红颜色位置,结果如何结果为:图13:程序运行结果答:ret的值变为了2
9、0c. 将程序中int a=20 int*p=&a;语句置换成蓝颜色语句,结果又如何?图14:程序运行结果答:ret的值变为了10(3) 总结:我们在接受子线程的返回值时,要注意设置为全局变量或者采用动态内存分配的方法才不会影响到系统的其他功能,保证程序运行过程无误且顺利。同时我们使用到了pthread_exit() 和pthread_join() 来控制线程,要注意的是pthread_exit() 终止线程,但不释放非分离线程的内存空间;当调用pthread_join()时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。当pthread_join()函数返回后,被
10、调用线程才算真正意义上的结束,它的内存空间也会被释放(如果被调用线程是非分离的)。这里有三点需要注意:被释放的内存空间仅仅是系统空间,你必须手动清除程序分配的空间,比如malloc()分配的空间。一个线程只能被一个线程所连接。被连接的线程必须是非分离的,否则连接会出错。同时我们深入了解pthread_join() 后可以得知,在Linux中一个线程只可能是可连接或者可分离。我们创建一个线程的时候,线程默认是可连接。可连接和可分离的线程有以下的区别:线程类型说明可连接的线程能够被其他线程回收或杀死,在其被杀死前,内存空间不会自动被释放可分离的线程不能被其他线程回收或杀死,其内存空间在它终止时由系
11、统自动释放我们可以看到,对于可连接的线程而而言,它不会自动释放其内存空间。因此对于这类线程,我们必须要配合使用pthread_join()函数。而对于可分离的函数,我们就不能使用pthread_join()函数。五、 分析与讨论通过这一次的实验,我对线程的控制和管理有了更多的了解,也学会了如何创建线程和线程间的参数访问,也懂得了线程函数返回简单数据类型的值和返回复杂数据类型的值的原理和所用到的函数,明白了pthread_create()、getpid()、pthread_self()、pthread_exit() 、pthread_join()、sleep()等等函数,对于线程的整个运行过程和运行方式有了更加深入地体会,让我对linux操作系统的学习更加得心应手了。六、教师评语签名:日期:成绩专心-专注-专业