We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
有一个名叫大自然的搬运工的工厂,生产一种叫做一氧化二氢的神秘液体。这种液体的分子是由一个氧原子和两个氢原子组成的,也就是水。 这个工厂有多条生产线,每条生产线负责生产氧原子或者是氢原子,每条生产线由一个 goroutine 负责。 这些生产线会通过一个栅栏,只有一个氧原子生产线和两个氢原子生产线都准备好,才能生成出一个水分子,否则所有的生产线都会处于等待状态。也就是说,一个水分子必须由三个不同的生产线提供原子,而且水分子是一个一个按照顺序产生的,每生产一个水分子,就会打印出 HHO、HOH、OHH 三种形式的其中一种。HHH、OOH、OHO、HOO、OOO 都是不允许的。 生产线中氢原子的生产线为 2N 条,氧原子的生产线为 N 条。
有一个名叫大自然的搬运工的工厂,生产一种叫做一氧化二氢的神秘液体。这种液体的分子是由一个氧原子和两个氢原子组成的,也就是水。
这个工厂有多条生产线,每条生产线负责生产氧原子或者是氢原子,每条生产线由一个 goroutine 负责。
这些生产线会通过一个栅栏,只有一个氧原子生产线和两个氢原子生产线都准备好,才能生成出一个水分子,否则所有的生产线都会处于等待状态。也就是说,一个水分子必须由三个不同的生产线提供原子,而且水分子是一个一个按照顺序产生的,每生产一个水分子,就会打印出 HHO、HOH、OHH 三种形式的其中一种。HHH、OOH、OHO、HOO、OOO 都是不允许的。
生产线中氢原子的生产线为 2N 条,氧原子的生产线为 N 条。
首先,我们来定义一个 H2O 辅助数据类型,它包含两个信号量的字段和一个循环栅栏。
package main import ( "context" "github.com/marusama/cyclicbarrier" "golang.org/x/sync/semaphore" ) // 定义水分子合成的辅助数据结构 type H2O struct { semaH *semaphore.Weighted // 氢原子的信号量 semaO *semaphore.Weighted // 氧原子的信号量 b cyclicbarrier.CyclicBarrier // 循环栅栏,用来控制合成 } func New() *H2O { return &H2O{ semaH: semaphore.NewWeighted(2), //氢原子需要两个 semaO: semaphore.NewWeighted(1), // 氧原子需要一个 b: cyclicbarrier.New(3), // 需要三个原子才能合成 } }
接下来,我们看看各条流水线的处理情况。
流水线分为氢原子处理流水线和氧原子处理流水线,首先,我们先看一下氢原子的流水线:如果有可用的空槽,氢原子的流水线的处理方法是 hydrogen,hydrogen方法会占用一个空槽(h2o.semaH.Acquire),输出一个 H 字符,然后等待栅栏放行。等其它的 goroutine 填补了氢原子的另一个空槽和氧原子的空槽之后,程序才可以继续进行。
hydrogen
h2o.semaH.Acquire
goroutine
func (h2o *H2O) hydrogen(releaseHydrogen func()) { h2o.semaH.Acquire(context.Background(), 1) releaseHydrogen() // 输出H h2o.b.Await(context.Background()) //等待栅栏放行 h2o.semaH.Release(1) // 释放氢原子空槽 }
然后是氧原子的流水线。氧原子的流水线处理方法是oxygen, oxygen 方法是等待氧原子的空槽,然后输出一个 O,就等待栅栏放行。放行后,释放氧原子空槽位。
oxygen
func (h2o *H2O) oxygen(releaseOxygen func()) { h2o.semaO.Acquire(context.Background(), 1) releaseOxygen() // 输出O h2o.b.Await(context.Background()) //等待栅栏放行 h2o.semaO.Release(1) // 释放氢原子空槽 }
在栅栏放行之前,只有两个氢原子的空槽位和一个氧原子的空槽位。只有等栅栏放行之后,这些空槽位才会被释放。栅栏放行,就意味着一个水分子组成成功,流水线才能继续运输和面的H和O原子。
两条流水线上执行的输送原子操作可以定义如下
// 用来存放水分子结果的channel var ch chan string // 往channel里存放一个H原子 func releaseHydrogen() { ch <- "H" } // 往channel里存放一个O原子 func releaseOxygen() { ch <- "O" }
在channel的另一端,就能以两个H原子一个O原子的组合不断接受到流水线运送过来的原子,组合成H2O水分子。
channel
查看完整源代码
The text was updated successfully, but these errors were encountered:
No branches or pull requests
题目是这样的:
实现思路
首先,我们来定义一个 H2O 辅助数据类型,它包含两个信号量的字段和一个循环栅栏。
接下来,我们看看各条流水线的处理情况。
流水线分为氢原子处理流水线和氧原子处理流水线,首先,我们先看一下氢原子的流水线:如果有可用的空槽,氢原子的流水线的处理方法是
hydrogen
,hydrogen
方法会占用一个空槽(h2o.semaH.Acquire
),输出一个 H 字符,然后等待栅栏放行。等其它的goroutine
填补了氢原子的另一个空槽和氧原子的空槽之后,程序才可以继续进行。然后是氧原子的流水线。氧原子的流水线处理方法是
oxygen
,oxygen
方法是等待氧原子的空槽,然后输出一个 O,就等待栅栏放行。放行后,释放氧原子空槽位。在栅栏放行之前,只有两个氢原子的空槽位和一个氧原子的空槽位。只有等栅栏放行之后,这些空槽位才会被释放。栅栏放行,就意味着一个水分子组成成功,流水线才能继续运输和面的H和O原子。
两条流水线上执行的输送原子操作可以定义如下
在
channel
的另一端,就能以两个H原子一个O原子的组合不断接受到流水线运送过来的原子,组合成H2O水分子。查看完整源代码
The text was updated successfully, but these errors were encountered: