一、 实践目的
1) 学习多线程操作(Pthread库)
2) 学习Linux中PV操作对应的实现
二、实践环境
1)Vmware WorkStation Pro
2)虚拟机操作系统:Ubuntu20.04
三、问题描述
桌上有一只盘子,每次只能放入一个水果。爸爸专放苹果,妈妈专放橘子,一个儿子专等吃盘子中的橘子,一个女儿专等吃盘子中的苹果。分别用P、V操作和管理实现。
四、实践内容
·线程和进程的互斥和同步
同步是操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享和进程协作,从而避免进程之间的冲突,引入进程同步。
进程互斥是间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。
·信号量和P、V操作
通过设置一个表示资源个数的信号量S,通过对信号量S的P、V操作来实现进程的同步与互斥。P、V操作分别来自荷兰语Passeren和Vrijgeven,分别表示占有和释放。P、V操作是操作系统的原语,意味着具有原子性。
P操作首先减少信号量,表示有一个进程将占有或等待资源,然后检测S是否小于0,如果小于0则阻塞,如果大于0则占有资源进行执行。
V操作是和P操作相反的操作,首先增加信号量,表示占用或等待资源的进程减少了1个。然后检测S是否小于0,如果小于0则唤醒等待使用S资源的其它进程。
·题目分析
(1)设有两个篮子,分别有若干个苹果或橘子,爸爸和妈妈将每次从水果篮子中拿出一个水果放入水果盘中,儿子女儿则挑选各自喜欢的水果。
(2)Father、mother、son、daughter是四个线程或进程。
(3)盘子plate是它们的共享变量,对盘子的操作要互斥。
(4)Father和daughter要对apple同步。
(5)Mother和son要对orange同步。
·用P、V操作实现(伪代码)
bash
empty,full1,full2:semaphore;
empty:=1;full1:=0;full2:=0;
cobegin
repeat father;
repeat mother;
repeat son;
repeat daughter;
coend;
procedure father
begin
p(empty);
放苹果入盘:
v(full1);
end;
procedure mother
begin
p(empty);
放橘子入盘;
v(full2);
end;
procedure son
begin
p(full2);
从盘中取橘子;
v(empty);
吃橘子;
end;
procedure daughter
begin
p(full1);
从盘中取苹果;
v(empty);
吃苹果;
end;
·实验过程
(1)安装必要的库,包括POSIX线程(pthread)和信号量(semaphore)。



(2)创建一个fruit_plate.c文件,并编写代码。键入vim fruit_plate.c进行编写。




在该程序中,为了让进程在有限次数内结束循环,我假定爸爸手头有五个苹果A,B,C,D,E,妈妈手头有五个橘子A,B,C,D,E。并引入usleep函数来模拟爸爸放苹果的时间为1秒,妈妈放橘子的时间为1.5秒,儿子吃橘子的时间为2秒,女儿吃苹果的时间为2.5秒。sem_wait和 sem_post分别对应P和V操作,用于同步和互斥。sem_init初始化信号量,sem_destroy销毁信号量。pthread_create创建线程,pthread_join等待线程结束。信号量 plate_sem用于互斥访问盘子,确保每次只有一个线程可以放入或取走水果。信号量 apple_sem和 orange_sem用于同步,确保女儿和儿子只有在有对应的水果时才能吃。
(3)键入gcc -pthread fruit_plate.c -o fruit_plate编译代码。

(4)键入./fruit_plate运行生成的可执行文件。

五、 小结与改进设想
本次实践后,我对线程和进程也有了更深更具体的体会。进程是具有一定独立 功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调 度的一个独立单位。线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是 比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源 (如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。 具体区别如下:
地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
通信:线程间可以直接读写进程数据段(如全局变量)来进行通信------需要进程同步和互斥手段的辅助,以保证数据的一致性。
调度和切换:线程上下文切换比进程上下文切换要快得多。