• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

Recommended Posts

OO_Unit2_多线程

一、同步块 与 锁

在本实验中,只有以下两种形式用于同步:

//格式1

同步(锁定){

//代码块

}

//格式2

尝试{

lock . wait();

} catch (InterruptedException e) {

e . printstacktrace();

}

//在其他代码块中

lock . notifyall();

不同的线程在访问共享资源时可能会产生写冲突,所以使用同步块和锁来控制对共享资源的访问3354只有一个线程可以同时读写共享资源(使用读写分离模式可以提高效率,因为只有写操作可能会产生冲突)。

关键词synchronized(同步锁):给所有同步控制区添加同步锁(同一个线程可以重新进入同一个对象锁,同一个线程可以多次获取同一个锁。3354支持多次重入)。通常,在同步控制区域中使用wait-notify/notifyAll方法来避免轮询。

当一个线程访问共享资源,发现锁被其他线程持有时,它使用wait to wait来防止轮询消耗CPU资源,直到其他线程释放锁,然后通知/notifyAll来唤醒等待的线程。

二、架构 与 设计模式

考虑到请求是通过时间戳输入的,需要独占一个线程,并行运行的电梯也对应多个并行线程,请求作为共享资源停留在相应的楼层和构建块上,使用生产者-消费者设计模式刚好合适,将输入线程视为生产者,将电梯视为消费者。结合特定于线程的存储模式,为每个电梯和构建块分配单独的存储空间,以避免所有线程共享同一个等待队列(共享资源)所导致的冗余。

这里给出了基于线程交互的UML类图,省略了一些类的一些细节,重点放在类之间的关系上。

imqw0dkqnqe2845.png

在HW5阶段,只有三个关键类:BuildingElevator、WaitList和RequestTable,它们使用标准的生产者-消费者设计模式。BuildingElevator对应消费者,RequestTable对应生产者,WaitList对应渠道,PersonRequest对应数据,形成类似下图的结构。

2ontsouplso2846.png

在HW5到HW6的迭代开发过程中,由于对跨层请求的限制(跨层请求不涉及换层),问题可以简单地转化为增加十个水平楼层,引入FloorElevator,整体上类似于BuildingElevator,只需要稍微修改一下操作逻辑3354,将上下运动改为顺时针和逆时针运动。

面对HW7的跨楼层请求,我们使用生产者-消费者设计模式的变种—— Worker Thread,然后结合流水线的设计思想,将请求进行划分,依次发送到水平电梯和垂直电梯。具体来说,我们为电梯添加—— Puts PersonRequest,这是一种与WaitList的交互模式,用于模拟转移到下一个流级别的行为。

22&i=blog/2806511/202205/2806511-20220501004853752-320329915.png"/>

 

在实际处理中,为了让电梯正常结束而基于请求数设置了计数器,基本流程为:主线程启动调度器,调度器开始按时间戳输入请求并分发至等待队列,等待队列根据请求启动新电梯或维护新的到达请求。电梯则从其对应的等待队列中不断获取新的到达请求并进行处理,处理结束后不需换乘则与计数器进行交互,否则将部分处理后的到达请求返回给调度器由其决定该请求的下一步去向。最后,当计数器清零且输入结束即意味着所有线程可以结束了。

三、调度器 与 线程交互

调度器使用 单例模式,某种程度上类似于 全局变量 的用法,使得所有类均可直接使用调度器(通过 getInstance 方法获取对象)进行调度。

 public class RequestTable {
  private static final RequestTable REQUEST_TABLE = new RequestTable();
     
     public static RequestTable getInstance() {
         return REQUEST_TABLE;
    }
 }

调度器主要负责将请求进行分类,并分发至对应的等待队列。在 HW5 与 HW6 中,调度器 RequestTable 仅负责将输入分发给对应等待队列 WaitList ,而在 HW7 构建流水线结构后,它还负责将各级流水线未完全完成的 PersonRequest 进行重新分配,将其视为另一种输入。具体来说,可以在 Elevator 中调用调度器及其方法,来实现同一请求的流水级转换。

四、测试 与 Bug 修复

相较第一单元化简表达式而言,第二单元更趋向于简单的模拟,因此很难在逻辑上出现漏洞,所以保证电梯调度系统的各部分功能基本实现即可证明系统整体的正确性。需要额外关注的重点,在于如何处理多线程之间的关系:一方面要防止轮询,另一方面又要防止死等。

在 HW5 、HW6 及 HW7 的测试与 hack 阶段,都发现了轮询的问题,追查原因后发现问题均是由 wait 与 notifyAll 的不配对使用造成的——常常发生等待线程被无谓的唤醒从而浪费 CPU 资源的现象。因此,确保仅在改变需要被等待线程使用的共享资源后才进行唤醒,便可以避免此类轮询问题。

此外,在 HW7 中还发现了死等的问题,主要是由于引入流水线结构后未设置完备的结束逻辑,使得流水级在部分情况下无法判断输入是否真的结束。对此,仿照控制器设置一个单例模式的计数器来标记请求数目,便可以解决上述问题。虽然这样外挂一个额外的计数器较为不优雅,但若后续需要其他迭代开发,也可以选择将其内嵌至控制器中,作为控制器的子功能来实现。

五、心得体会

本单元主要考察多线程,与 OS 在多进程方面的内容有异曲同工之妙,关注的核心内容都是不同进程/线程对共享资源的写读冲突问题。由于这两方面内容几乎同时讲授,我的关注点也主要落在多线程设计模式上,考虑各种线程交互的模式以及代码的整体架构,而几乎忽视了面向对象属性,使得类、方法的层次设计十分丑陋。如果能将面向对象这一代码管理方法应用得当,设计模式的实现可能会更加轻松吧。

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now