我怎么知道我的所有 goroutine 确实正在使用 golang 的同步包等待一个条件

2024-05-14

我有一个应用程序,我正在创建多个 goroutine 来同时执行某个任务。所有工作协程都会等待条件/事件发生,一旦事件被触发,它们就会开始执行。创建完所有goroutines后,主线程在发送广播信号之前应该知道所有goroutines确实处于等待状态。

我知道这可以使用通道来完成(这是推荐的),但我也发现 go 的同步包很有趣。只是想弄清楚如何使用同步包而不是通道来实现相同的功能

package main

import (
    "fmt"
    "sync"
    "time"
)

var counter int

func worker(wg *sync.WaitGroup, cond *sync.Cond, id int) {
    fmt.Println("Starting Goroutine ID:", id)
    // Get a lock and wait
    cond.L.Lock()
    defer cond.L.Unlock()
    fmt.Println("Goroutine with ID: ", id, "obtained a lock")
    // Do some processing with the shared resource and wait
    counter++
    wg.Done()
    cond.Wait()
    fmt.Println("Goroutine ID:", id, "signalled. Continuing...")
}

func main() {
    var wg sync.WaitGroup
    cond := sync.NewCond(&sync.Mutex{})
    counter = 0
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(&wg, cond, i)
    }

    wg.Wait() // Wait()'ing only until the counter is incremented
    // How to make sure that all goroutines you created are indeed wait()'ing ?????
    cond.Broadcast()
    time.Sleep(2 * time.Second)
    cond.Broadcast()
    fmt.Println("Final value of the counter is", counter)
}

如果我在最后 3 行中不使用以下语句(fmt.Println 除外)

    time.Sleep(2 * time.Second)
    cond.Broadcast()

我得到以下输出..

Starting Goroutine ID: 4
Goroutine with ID:  4 obtained a lock
Starting Goroutine ID: 3
Goroutine with ID:  3 obtained a lock
Starting Goroutine ID: 1
Goroutine with ID:  1 obtained a lock
Starting Goroutine ID: 0
Goroutine with ID:  0 obtained a lock
Starting Goroutine ID: 2
Goroutine with ID:  2 obtained a lock
Final value of the counter is 5
Goroutine ID: 3 signalled. Continuing...

理想情况下,每个 goroutine 都应该能够打印

Goroutine ID: 3 signalled. Continuing...

以及相应的 goroutine id。我们无法打印它,因为并非所有 goroutine 都发出信号,因为其中一些 goroutine 甚至没有处于等待状态。这就是我添加 time.Sleep 的原因,这不是一个实际的解决方案。

我的问题是..我怎么知道所有的goroutine实际上都在等待条件cond.Wait()..Channels是一个解决方案,但我想知道如何使用go的sync包来做到这一点?


你有一个问题是Broadcast不保证唤醒所有的 goroutine,因为它只会唤醒已经在等待的 goroutine,并且之间有一个小窗口wg.Done() and cond.Wait()。通常,条件变量将与表示您用于同步的“条件”的变量一起使用。在这种情况下,您可以有一个bool包变量,指示 goroutine 是否可以继续。main会设置它,然后进行广播来告诉 goroutine 继续。例如:

package main

    import (
    "fmt"
    "sync"
)

var counter int
var start bool

func worker(wg *sync.WaitGroup, cond *sync.Cond, id int) {
    fmt.Println("Starting Goroutine ID:", id)
    // Get a lock and wait
    cond.L.Lock()
    fmt.Println("Goroutine with ID: ", id, "obtained a lock")
    // Do some processing with the shared resource and wait
    counter++
    if !start {
        cond.Wait()
    }
    cond.L.Unlock()
    fmt.Println("Goroutine ID:", id, "signalled. Continuing...")
    wg.Done() // Worker is completely done
}

func main() {
    var wg sync.WaitGroup
    cond := sync.NewCond(&sync.Mutex{})
    counter = 0
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(&wg, cond, i)
    }

    cond.L.Lock()
    start = true
    cond.Broadcast()
    cond.L.Unlock()

    wg.Wait() // Wait until all workers are done
    fmt.Println("Final value of the counter is", counter)
}

添加的start变量使得 goroutine 不可能在以下情况下停止继续:main告诉他们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我怎么知道我的所有 goroutine 确实正在使用 golang 的同步包等待一个条件 的相关文章

  • 无论线程如何,对象是否总是能看到其最新的内部状态?

    假设我有一个带有简单整数计数变量的可运行对象 每次可运行对象运行时该变量都会递增 该对象的一个 实例被提交以在计划的执行程序服务中定期运行 class Counter implements Runnable private int coun
  • 获取 Future 对象的进度的能力

    参考 java util concurrent 包和 Future 接口 我注意到 除非我弄错了 只有 SwingWorker 实现类才能启动冗长的任务并能够查询进度 这就引出了以下问题 有没有办法在非 GUI 非 Swing 应用程序 映
  • 如何在 Go 中使用与包同名的变量名?

    文件或目录的常见变量名称是 path 不幸的是 这也是 Go 中包的名称 此外 在 DoIt 中更改路径作为参数名称 如何编译此代码 package main import path os func main DoIt file txt f
  • 共享 GOPATH 的良好做法是什么?

    我刚刚开始学习 Go 并阅读现有代码以了解 其他人是如何做的 在这样做时 go 工作空间 的使用 特别是当它与项目的依赖项相关时 似乎无处不在 在处理各种 Go 项目时 使用单个或多个 Go 工作区 即 GOPATH 的定义 的常见最佳实践
  • Golang:如何在HTTP客户端的TLS配置中指定证书

    我有一个证书文件 该位置是 usr abc my crt我想将该证书用于我的 tls 配置 以便我的 http 客户端在与其他服务器通信时使用该证书 我当前的代码如下 mTLSConfig tls Config CipherSuites u
  • 重新设计循环依赖缺陷

    我有一堆小服务 它们共享一些常见的包 例如Logger Configuration and Net 我在单独的项目中编写了每个包 问题是我的Logger需求包Configuration用于设置 和我的Configuration not仅由L
  • Scala 中用于阻止调用的 Future

    The Akka文档说 you may be tempted to just wrap the blocking call inside a Future and work with that instead but this strate
  • Go的堆接口实现的优先级队列的大小限制

    在Java中 有一个具有大小属性 的PriorityQueue 我在这里也期待同样的事情 如果我没记错的话 用例 一一读取数百万数据并将其发送到优先级队列 我只想要前 5 个计算元素 因此我只想要大小为 5 的堆 优先级队列 我正在尝试使用
  • 在 Python 中发送 100,000 个 HTTP 请求的最快方法是什么?

    我正在打开一个包含 100 000 个 URL 的文件 我需要向每个 URL 发送 HTTP 请求并打印状态代码 我正在使用 Python 2 6 到目前为止 我已经了解了 Python 实现线程 并发的许多令人困惑的方式 我什至看过蟒蛇一
  • 如何覆盖 go 模块中的依赖项?

    In dep您可以选择覆盖依赖项并使其指向不同的存储库 例如以下内容https github com kubermatic glog logrus https github com kubermatic glog logrus库一需要将以下
  • go build 不断抱怨:go.mod 有 post-v0 模块路径

    Go 1 11 发布后 我一直在尝试将我的存储库移动到 Go 模块 方法是添加go mod文件在其根目录下 我的根库之一my host root其版本为17 0 1 所以我在其中写道go mod file module my host ro
  • 带有导出字段的私有类型

    在 Go 教程的第二天有这样的练习 为什么拥有带有导出字段的私有类型会很有用 例如 package geometry type point struct X Y int name string 请注意point是小写的 因此不会导出 而字段
  • 我的代码线程不安全吗?

    我编写了代码来理解 CyclicBarrier 我的应用程序模拟选举 每轮选出得票少的候选人 该候选人从竞争中淘汰以获得胜利 source class ElectoralCommission public volatile boolean
  • Golang:使用像 Node.js 中那样的可读流从 PostgreSQL 数据库中选择几百万行

    我有大约 5000 万行的 PostgreSQL 表 我想编写 Go 代码来从该表中选择大约 100 万行 并以有效的方式处理它们 上次我使用了nodejs和这个NPM模块pg 查询流 https www npmjs com package
  • GO中的优先级队列

    谁能向我解释一下 我想在GO中实现一个优先级队列 接口实现来自link https golang org pkg container heap example priorityQueue 但优先级最低 我的代码 pq make Priori
  • 控制启动时的竞争条件

    我有一些代码想要执行一些一次性初始化 但这段代码没有明确的生命周期 因此在初始化完成之前 我的逻辑可能会被多个线程调用 所以 我想基本上确保我的逻辑代码 等待 直到初始化完成 这是我的第一次剪辑 public class MyClass p
  • 在 Go 中,如何将函数的 stdout 捕获到字符串中?

    例如 在 Python 中 我可以执行以下操作 realout sys stdout sys stdout StringIO StringIO some function prints to stdout get captured in t
  • 正则表达式不匹配

    我正在尝试以下代码 d byte x01 x00 x00 x00 x00 x00 x00 x00 x00 x00 x00 x80J x13 x80SQ x80L xe0 x80 x92 x80L x80H xe0 r regexp Must
  • Go 编程 - 使用指针绕过访问权限

    假设我的项目有以下层次结构 fragment fragment go main go 并且在fragment go我有以下代码 只有一个 getter 没有 setter package fragment type Fragment str
  • 从 Go Slice 中选择一个随机值

    情况 我有一些值 需要从中随机选择一个值 然后我想将它与固定字符串连接起来 到目前为止 这是我的代码 func main create the reasons slice and append reasons to it reasons m

随机推荐

  • 如何在 iOS 中设置视图的最大宽度?

    我的应用程序有一个基本的登录屏幕 一个外框以及其中的一些文本字段和按钮 我将框设置为填满屏幕 然而 在某些设备上这个盒子会太大 如何设置视图的最大宽度和高度 您可以使用自动布局约束 使框适应屏幕尺寸 但不超过给定的宽度和高度 为此 请对宽度
  • NodeJS 在目录中递归地哈希文件

    我能够实现目录中的递归文件遍历 即探索目录中的所有子目录和文件 为此我使用了answer https stackoverflow com questions 5827612 node js fs readdir recursive dire
  • Android Camera.takePicture() 有时不返回?

    我正在编写一个Android 拍照应用程序 该代码在 onPreviewFrame byte data Cameracamera 中从预览中获取帧后进行一些处理 问题在于 android hardware Camera 的函数 takePi
  • 关于 C 中的 switch{} 情况?

    我正在读一些文字C language 文字说switch case只能接受整数类型 我只是好奇为什么switch case不接受其他类型 例如浮点数或字符串 这背后有什么原因吗 多谢 经典的原因可能是对于整数值的 决策表达式 可以进行非常好
  • java程序有多少种结束方式?

    我知道使用 System exit 0 可以结束一个java程序 例如 如果我有一个JFrame窗口 它会关闭并结束程序 但我想知道还有多少其他方法 可以关闭它并结束程序 包括发生错误时 程序会被关闭 JFrame也会被关闭吗 添加到其他答
  • 在 UIView 中绘制彩色文本 -drawRect: 方法

    我正在尝试在我的中绘制彩色文本UIView子类 现在我正在使用单视图应用程序模板 用于测试 除了以下内容外 没有任何修改drawRect method 文本已绘制 但无论我将颜色设置为什么 它始终是黑色的 void drawRect CGR
  • Facebook Graph API 中不支持 get 请求

    由于某种原因我的https graph facebook com 210155825774263 https graph facebook com 210155825774263返回错误 error message Unsupported
  • AttributeError:'function'对象在pandas中没有属性'bar'

    我有一个 pandas 数据框 它是 pandas 数据框类型 如下所示 type df Out 176 pandas core frame DataFrame 但是 当我尝试在此数据框上使用任何绘图函数 如条形图 时 会出现如下错误 df
  • 无法解析类型“Microsoft.ApplicationInsights.TelemetryClient”的服务

    我已将我的 Web 项目从 RC1 迁移到 RC2 但出现以下错误 无法解析类型的服务 尝试时出现 Microsoft ApplicationInsights TelemetryClient 启用 Microsoft Application
  • OSX/Mac 中的插件持久设置

    我无法找到在 Mac 上存储 Office js 加载项的持久设置的方法 在 Windows 上 localStorage 工作得非常完美 因为它可以保存关闭和打开 Word 时仍保留的设置 在 Mac 上 localStorage 不会持
  • Cordova - 启动后出现白屏,控制台中没有例外

    我已经离开我的 Cordova 应用程序一段时间了 但昨天刚刚进行了一次新的克隆 发现它出现了 死机白屏 症状 启动画面显示 程序加载 然后我就得到一个空白屏幕 更多细节 CLI 科尔多瓦 6 1 1 安卓 5 1 1 ios 4 1 1
  • 为什么 { } 初始化需要 Add 方法?

    要使用这样的初始化语法 var contacts new ContactList Dan email protected cdn cgi l email protection Eric email protected cdn cgi l e
  • 将对象的值插入到span标签中

    我有一个对象 message text Here is some text 我想将它插入到一个跨度标签中 如下所示 span message text span 这不会打印 这是一些文本 而是只会在网页上显示 message text 我怎
  • 虚拟回调接口

    在 Eclipse 为您创建的来自 Google 的示例主从流代码中 片段中包含以下内容 private Callbacks mCallbacks sDummyCallbacks public interface Callbacks pub
  • 连接数组时合并两个 yaml 文档

    我想合并两个 yaml 文档 结果包含 所有映射值 最后一个优先 串联数组 例如给定这个文件 file1 yml animals elephant donkey flavours sour lemon sweet chocolate str
  • 仅当环境变量具有特定值时如何设置 Apache 标头

    我想在我的 Apache 2 4 配置中设置标头 但前提是环境变量具有特定值 SetEnv ENV NAME prod 我如何仅在以下情况下设置此标头ENV NAME is not prod Header set X Robots Tag
  • 如何使用放心的方式在正文中发送 JsonObject 以进行 post 请求?

    我有一个使用 Google Gson 创建的 JsonObject JsonObject jsonObj gson fromJson response1 json JsonElement class getAsJsonObject 我还对现
  • 设置 IRQ 映射

    我正在遵循一些教程和参考文献来尝试设置我的内核 我在教程中遇到了一些不熟悉的代码 但根本没有解释它 这是我被告知映射的代码16 IRQs 0 15 到 ISR 地点32 47 void irq remap void outportb 0x2
  • 哪里可以找到可靠的 K-medoid(不是 k-means)开源软件/工具? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在学习 K medoids 算法 所以如果我提出不恰当的问题 我很抱歉 据我所知 K medoid
  • 我怎么知道我的所有 goroutine 确实正在使用 golang 的同步包等待一个条件

    我有一个应用程序 我正在创建多个 goroutine 来同时执行某个任务 所有工作协程都会等待条件 事件发生 一旦事件被触发 它们就会开始执行 创建完所有goroutines后 主线程在发送广播信号之前应该知道所有goroutines确实处