一、实验目的
(1)理解操作系统线程的概念和应用编程过程;
(2)理解线程的同步概念和编程;

二、实验内容
(1)在 Ubuntu 或 Fedora 环境使用 fork 函数创建一对父子进程,分别输出各自的进程号和提示信息串。
(2)在 Ubuntu 或 Fedora 环境使用 pthread_create 函数创建2 个线程 A 和 B。线程 A 在屏幕上用 while 循环顺序递增地输出 1-1000 的自然数;线程 B 在屏幕上用 while 循环顺序递减地输出1000-1 之间的自然数。为避免输出太快,每隔 0.5 秒输出一个数。
(3)在 windows 环境下,利用高级语言编程环境(限定为 VS 环境或 VC 环境)调用 CreateThread 函数实现(2)的功能。
(4)在 windows 环境下,利用高级语言编程环境(限定为 VS 环境或 VC 环境)调用 CreateThread 函数和相关的同步函数,模拟实现“生产者-消费者”问题。
(5)在 windows 环境下,利用高级语言编程环境(限定为 VS环境或 VC 环境)调用 CreateThread 函数实现“并发地画圆和画方”。圆的中心,半径,颜色,正方形的中心,边长,颜色等参数自己确定,合适就行。圆和正方形的边界上建议取 720 个点。为直观展示绘制的过程,每个点绘制后睡眠 0.2 秒~0.5 秒。

三、实验过程
(一)实验步骤
1)fork函数创建父子进程
1.打开ubuntu上文本编辑器写c程序(problem1.c)
2.核心代码

1.   void main()
2.  {   pid_t pid;
3.      fprintf(stdout,"I am the first process, my pid is %d, my parent pid is %d\n",getpid(),getppid());
4.      pid=fork();
5.      if(0==pid)
6.          fprintf(stdout,"I am the child process, my pid value is %d, but my real pid is %d, my parent pid is %d\n",pid,getpid(),getppid());
7.      else
8.          fprintf(stdout,"I am the parent process, my child pid value is %d, my real pid is %d, my parent pid is %d\n",pid,getpid(),getppid());
9.  }

3.第3行要求输出当前进程的pid和他的父进程的pid,第4行的pid是fork()函数的返回值,第6和7行分别输出不同进程运行时的信息(getpid(),getppid()分别返回进程和其父进程的pid)
4.在终端上编译该程序并输出结果
#gcc problem1.c
#./a.out
5.分析结果

2)pthread_create 函数创建2 个线程(problem2.c)
1.打开ubuntu上文本编辑器写c程序
2.核心代码

10.  int main()
11. {12.     pthread_t tips1;
13.     pthread_t tips2;
14.     int hThread1 = pthread_create(&tips1, NULL, print1, NULL);
15.     int hThread2 = pthread_create(&tips2, NULL, print2, NULL);
16.     if (hThread1 != 0)
17.     {18.         printf("hThread1 err");
19.     }
20.     else if (hThread2 != 0)
21.     {22.         printf("hThread2 err!");
23.     }
24.     void *result1;
25.     void *result2;
26.     pthread_join(tips1, &result1);
27.     pthread_join(tips2, &result2);
28.     return 0;
29.     }
  1. pthread_create(,,,)创建线程,第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。返回值: 若成功则返回0,否则返回出错编号
    pthread_join(,)用来等待一个线程的结束。第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。如果执行成功,将返回0,如果失败则返回一个错误号。
    4.在终端上编译该程序并输出结果
    #gcc problem1.c -lpthread
    #./a.out
    5.分析结果
    3)VS 环境实现(2)的功能
    1.打开VS写c程序(problem3.cpp)
    2.核心代码
30.  int main()
31. {32.     HANDLE hThread[2];
33.     //创建线程,并调用函数打印输出
34.     hThread[0] = CreateThread(NULL, 0, print1, (LPVOID)1000, 0, NULL);
35.     hThread[1] = CreateThread(NULL, 0, print2, (LPVOID)1, 0, NULL);
36.     //等待所有线程结束
37.     WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
38.
39.     CloseHandle(hThread[0]);
40.     CloseHandle(hThread[1]);
41.
42.     return 0;
43. }
  1. 在C/C++中可以通过CreateThread函数在进程中创建线程,函数的具体格式如下:
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadID);

参数的含义如下:
lpThreadAttrivutes:指向SECURITY_ATTRIBUTES的指针,用于定义新线程的安全属性,一般设置成NULL;
dwStackSize:分配以字节数表示的线程堆栈的大小,默认值是0;
lpStartAddress:指向一个线程函数地址。每个线程都有自己的线程函数,线程函数是线程具体的执行代码;
lpParameter:传递给线程函数的参数;
dwCreationFlags:表示创建线程的运行状态,其中CREATE_SUSPEND表示挂起当前创建的线程,而0表示立即执行当前创建的进程;
lpThreadID:返回新创建的线程的ID编号;
如果函数调用成功,则返回新线程的句柄,调用WaitForSingleObject函数等待所创建线程的运行结束。函数的格式如下:
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
参数的含义如下:
hHandle:指定对象或时间的句柄;
dwMilliseconds:等待时间,以毫秒为单位,当超过等待时间时,此函数返回。如果参数设置为0,则该函数立即返回;如果设置成INFINITE,则该函数直到有信号才返回。 4.调试并运行程序
5.分析结果

4)VS 环境模拟实现“生产者-消费者”问题
1.打开VS写c程序(problem4.cpp)
2. 线程并发的生产者-消费者模型:1.两个进程对同一个内存资源进行操作,一个是生产者,一个是消费者。2.生产者往共享内存资源填充数据,如果区域满,则等待消费者消费数据。3.消费者从共享内存资源取数据,如果区域空,则等待生产者填充数据。4.生产者的填充数据行为和消费者的消费数据行为不可在同一时间发生。、
3.核心代码

44.  DWORD WINAPI producer(LPVOID v)
45. {46.     int item;
47.     while (true)
48.     {49.         item = produce_item();
50.         empty--;
51.         if (empty < 0)
52.             empty++;
53.         else if (mutex > 0)
54.         {55.             mutex--;
56.             insert_item(item);
57.             full++;
58.             mutex++;
59.         }
60.         Sleep(2000);
61.     }
62.     return 1;
63. }
64.
65. DWORD WINAPI consumer(LPVOID v)
66. {67.     int item;
68.     while (true)
69.     {70.         full--;
71.         if (full < 0)
72.             full++;
73.         else if (mutex > 0)
74.         {75.             mutex--;
76.             item = remove_item();
77.             empty++;
78.             mutex++;
79.         }
80.         Sleep(2000);
81.     }
82.     return 1;
83. }
  1. DWORD WINAPI producer(LPVOID v), DWORD WINAPI consumer(LPVOID v)表示生产者和消费者两个线程,通过PV操作使二者有效并发运行;两线程在缓冲区互斥,定义信号量mutex=1(初值);用full和empty表示缓冲区存储情况;insert_item(item),remove_item()表示向缓冲区中存储和移除数据。
    4.调试并运行程序
    5.分析结果
    5)VS环境并发地画圆和画方
    1.打开VS写c程序(problem5.cpp),先用EasyX创建画布
    2.核心代码
 DWORD WINAPI circle(LPVOID n)
85. {86.     double r = 200.0,x0=250.0,y0=250.0;//半径与圆心
87.     int x1,x2,y;
88.     for (y=50;y<=450;y+=6)
89.     {90.         double yy = sqrt(r*r-(y-y0)*(y-y0));
91.         x1 = x0 - yy;
92.         x2 = x0 + yy;
93.         outtextxy(x1,y,c);
94.         Sleep(100);
95.         outtextxy(x2,y,c);
96.         Sleep(100);
97.     }
98.     return 0;
99. }
100.
101.    //画方
102.    DWORD WINAPI tangle(LPVOID n)
103.    {104.        int mx = 540, my = 50;//左上角
105.        for (; my < 300; my+=10)
106.        {107.            outtextxy(mx,my,c);
108.            Sleep(100);
109.        }
110.        for (; mx < 940; mx += 10)
111.        {112.            outtextxy(mx, my, c);
113.            Sleep(100);
114.        }
115.        for (; my > 50; my -= 10)
116.        {117.            outtextxy(mx, my, c);
118.            Sleep(100);
119.        }
120.        for (; mx > 540; mx -= 10)
121.        {122.            outtextxy(mx, my, c);
123.            Sleep(100);
124.        }
125.        return 0;}

3.在画布上将圆和矩形的边以点的形式一个个输出,通过使用EasyX上的outtestxy()函数,利用圆和矩形上的点的坐标更加方便。
4.调试并运行程序
5.分析结果

(二)解决错误和优化
1. 操作过程错误,在终端编译c语言程序时找不到相应文件。因为我把c程序保存在了桌面上,终端默认位置为主目录,所以找不到,把文件移动到主目录即可。
2. 特殊语法错误,输出程序运行结果时出错。把命令输错了,应该为#./a.out,不要忽略“.”。
3.编译错误,problem2.c无法编译。在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库。

4.特殊的语法错误,

当调用CloseHandle成功后,相关的内核对象的引用计数被减1。这个函数做的工作就这么多。它并没有真正的关闭内核对象,只是将计数减1,CreateThread()返回值正确即可。

5.运行错误,生产者和消费者存取数不对。两个PV操作没有合理安排顺序,导致出错。画图分析PV操作先后执行顺序。

6.运行错误,圆和矩形的形状发生了错误。刚开始没使用EasyX画图,使用空格来确定坐标,导致圆和矩形的空格发生错乱,导致形状出错。

使用EasyX创建画布后,可以直接利用画布上的坐标,从而避免错误。
7.运行错误,矩形的边长输出为空。原因是坐标之间的间隔太小,字符相互重叠,结果全部都无法显示,把字符间的距离调大即可。

四、实验结果
1)fork函数创建父子进程

fork()函数在不同进程上下文返回不同的值,在父进程中返回子进程的pid,在子进程中返回0,若出错则返回一个负数;
输出的第一句为当前进程和其父进程的pid,当前进程pid为18239,然后创建子进程,pid在父进程中为18240,在子进程中为0;输出的第二句为父进程输出,第三句为子进程输出。

2)pthread_create 函数创建2 个线程


由图可知,两个线程并发运行成功。

3)VS 环境实现(2)的功能

由图可知,两个线程并发运行成功。

4)VS 环境模拟实现“生产者-消费者”问题

有图像可知,生产者和消费者两者生产和消费同时执行且互不耽误,缓冲区中存取的数和被取出的数正确。

5)VS环境并发地画圆和画方



由图可知,双线程并发地画圆和画方成功实现。

五、体会
通过本次实验,我对父子进程和多线程有了初步的了解,可以理解PV操作的意义并掌握其用法,以后的编程中可以更加巧妙地处理一些问题;但目前的熟练程度还不够,仍需多加练习。

《操作系统原理》实验报告二相关推荐

  1. 通信使用matlab三元码实验报告,Matlab仿真DSBSC信号与双极性不归零码通信原理实验报告二实验...

    Matlab仿真DSBSC信号与双极性不归零码通信原理实验报告二实验 Matlab 仿真 DSB-SC 信号与双极性不归零码通信原理实验报告二实验题目:Matlab 仿真 DSB-SC 信号与双极性不 ...

  2. ZUCC_操作系统原理实验_实验九 消息队列

    操作系统原理实验报告 课程名称 操作系统原理实验 实验项目名称 实验九 消息队列 实验目的 了解 Linux 系统的进程间通信机构 (IPC): 理解Linux 关于消息队列的概念: 掌握 Linux ...

  3. 操作系统原理实验-进程同步

    操作系统原理实验报告 实验题目 实验二进程同步 实验二.进程同步 1.1 实验目的 现代操作系统的核心是多道程序设计.多处理器和分布式处理器,这些方案和操作系统设计技术的基础都是并发.当多个进程并发执 ...

  4. 操作系统原理实验二(三)

    继续完成操作系统原理的实验 4.5(实验目的:熟悉Window线程创建过程)在windows环境下,利用高级语言编程环境(限定为VS环境或VC环境)调用CreateThread函数实现"并发 ...

  5. 进程同步算法实现实验报告Linux,操作系统进程同步实验报告.doc

    操作系统进程同步实验报告 实验三:进程同步实验 一.实验任务: (1)掌握操作系统的进程同步原理: (2)熟悉linux的进程同步原语: (3)设计程序,实现经典进程同步问题. 二.实验原理: (1) ...

  6. 东北大学软件学院操作系统v实验报告

    课程编号:B080000070     <操作系统>实验报告             姓名   学号   班级   指导教师   实验名称 <操作系统>实验 开设学期 2016 ...

  7. 配置微型计算机实验报告,微型计算机原理实验报告.docx

    微型计算机原理实验报告 微型计算机原理实验报告专业班级: 通信工程2013级 学生姓名: 周博文 学 号: 2013221105200097 完成时间: 2015月12月 实验一 运行并分析Hello ...

  8. 计算机网络实验报告二

    计算机网络实验报告二 目录 计算机网络实验报告二 1. 数据链路层 1.1 实验一 熟悉 Ethernet 帧结构 1.2 实验二 了解子网内/外通信时的 MAC 地址 1.3 实验三 掌握 ARP ...

  9. mysql数据库原理实验报告_数据库原理实验报告(Mysql).doc

    数据库原理实验报告(Mysql).doc 实验项目列表 序号实验项目名称指导教师1实验一 数据库的定义实验(验证性)2实验二 数据库的建立和维护实验(验证性)3实验三 数据库的查询实验(验证性)4实验 ...

  10. 微型计算机原理实验报告总结,微机原理实验报告-两个多位十进制数相加的实验等.doc...

    微机原理实验报告-两个多位十进制数相加的实验等.doc 微机原理实验报告班级学号姓名实验一两个多位十进制数相加的实验一.实验目的学习数据传送和算术运算指令的用法熟悉在PC机上建立.汇编.链接.调试和运 ...

最新文章

  1. Git与Svn的区别—笔记1
  2. Python 之 Numpy (五)合并
  3. 编译cscope-15.8a遇到的问题与解决方案
  4. 死锁 预防死锁避免死锁_死锁和处理死锁的方法
  5. jmu-枚举WeekDay
  6. RocketMQ入门到入土(五)消息持久化存储源码解析
  7. SQL Server 2008的安装
  8. python动态是什么意思_怎么看出自己是Python什么阶段
  9. 文献管理三剑客之NoteExpress和Endnote文献的管理,写论文时参考文献的格式
  10. Sentaurus TCAD Inspect
  11. 工程、技术与工程师三者之间的相互关系
  12. 匹配区县代码_省份、城市、区县三级联动Html代码
  13. 关于安装Spacy以及de和en模块遇到的坑---附最终解决方案
  14. 身边已经消失或走在消失路上的可爱小动物
  15. Android中淡入淡出动画
  16. vue {{}}中小数保留几位小数的toFixed(小数位数)方法
  17. 更聪明地学习,而不是苦读——《如何高效学习》
  18. html5 canvas实现高并发视频弹幕功能
  19. 变量的作用域和生存期:_生存分析简介:
  20. vscode调试C/C++报错:the program has exited with code 42 (0x0000002a).

热门文章

  1. TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute
  2. 一个简单的socket套接字服务器,Python
  3. java关键字super指什么_java 关键字super详解及用法
  4. mysql不等于条件不包含NULL值问题
  5. Eclipse无法启动
  6. Mysql动态sql之mybatis动态sql
  7. WebRequest 类和 WebResponse 类
  8. windows电脑启动问题-0xc000000d
  9. linux上传本地文件
  10. ATTck 入口点 —— 其他攻击