【问题标题】:Issue with runtime.LockOSThread() and runtime.UnlockOSThreadruntime.LockOSThread() 和 runtime.UnlockOSThread 的问题
【发布时间】:2011-12-05 07:07:21
【问题描述】:

我有一个类似的代码,

Routine 1 {
runtime.LockOSThread()
print something
send int to routine 2
runtime.UnlockOSThread

}

Routine 2 {
runtime.LockOSThread()
print something
send int to routine 1
runtime.UnlockOSThread

}


main {
go Routine1
go Routine2
}

我使用运行时锁定解锁,因为我不想打印 例程 1 将与例程 2 混合。但是,在执行上述操作后 代码,它的输出与没有锁定解锁相同(意味着打印输出 混合)。任何人都可以帮助我为什么会发生这种情况以及如何强制 这是为了发生。

注意:我举了一个打印的例子,但是有很多 打印和发送事件。

【问题讨论】:

    标签: go


    【解决方案1】:

    如果你想序列化“打印一些东西”,例如每个“打印内容”都应该以原子方式执行,然后序列化它。

    您可以用互斥体包围“打印某些东西”。除非代码因此而死锁,否则它会起作用——而且它肯定很容易在一个非平凡的程序中。

    在 Go 中序列化某些东西的简单方法是使用通道来完成。在(go)例程中收集应该一起打印的所有内容。打印单元的收集完成后,通过通道将其作为“打印作业”单元发送给某个打印“代理”。该代理将简单地接收其“任务”并自动打印每个任务。一个人免费获得这种原子性,作为一个重要的好处,代码在简单的情况下不再容易死锁,在这种情况下,只有非相互依赖的“打印单元”生成 goroutine。

    我的意思是这样的:

    func printer(tasks chan string) {
            for s := range tasks {
                    fmt.Printf(s)
            }
    }
    
    func someAgentX(tasks chan string) {
            var printUnit string
            //...
            tasks <- printUnit
            //...
    }
    
    func main() {
            //...
            tasks := make(chan string, size)
            go printer(tasks)
            go someAgent1(tasks)
            //...
            go someAgentN(tasks)
            //...
            <- allDone
            close(tasks)
    }
    

    【讨论】:

    • 我用过这个。但是,不仅在 lock 和 unlock 之间打印一些东西,还有一些发送事件,比如将 int 发送到例程 1。我也必须涵盖这些。您能对此提出任何建议吗?
    • @Arpssss:不,我不能提出任何具体的建议。如果不了解您正在解决的(整个)问题,这几乎是不可能的。但可能没有人会深入研究数百行代码。如果无法用少量代码或任何其他简洁明了的方式解释问题,那么恐怕您在 SO 或其他任何地方都不走运。
    • 我也尝试使用同步互斥锁play.golang.org/p/CbdrRHvbnQ。但是,在该代码中,我无法理解为什么例程一个接一个地执行,而不是同时执行。你能提出任何关于同步互斥的逻辑或任何错误的建议吗?
    • Go 游乐场设计有限。它只运行单线程。它也被及时冻结,除了 stdio/stderr 之外没有文件访问权限,也许还有更多。您必须在本地运行您的代码才能访问完整/标准运行时环境。顺便说一句,在每个 goroutine 中锁定了这三个互斥锁的链接代码,虽然顺序不同,但由于我根本不理解它的含义,所以没有立即死锁,这让我很惊讶。我想它会在操场外与 GOMAXPROCS > 1 “按设计”陷入僵局。
    • 你是对的。在我的桌面应用程序中,它显示死锁。实际上,我正在尝试实现同步互斥机制。其中,当例程 1 正在执行 fmt.Println("value of z") 时,所有其他线程都被阻塞。对该实施有任何更正吗?
    【解决方案2】:

    runtime.LockOSThread 所做的是防止任何其他 goroutine 在同一线程上运行。它强制运行时创建一个新线程并在那里运行 Routine2。它们仍在同时运行,但在不同的线程上。

    您需要使用 sync.Mutex 或一些通道魔法来代替。

    您很少需要使用 runtime.LockOSThread,但它可以用于强制一些更高优先级的 goroutine 在它自己的线程上运行。

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var m sync.Mutex
    
    func printing(s string) {
        m.Lock() // Other goroutines will stop here if until m is unlocked
        fmt.Println(s)
        m.Unlock() // Now another goroutine at "m.Lock()" can continue running
    }
    
    func main() {
        for i := 0; i < 10; i++ {
            go printing(fmt.Sprintf("Goroutine #%d", i))
        }
    
        <-time.After(3e9)
    }
    

    【讨论】:

    • 我已经更改了我的问题以使其更清晰。关于锁解锁,你说的很对。但是,你能给出一个简单的示例代码吗,我如何在上面的示例中使用同步互斥锁。
    • 我也尝试使用同步互斥锁play.golang.org/p/CbdrRHvbnQ。但是,在该代码中,我无法理解为什么例程一个接一个地执行,而不是同时执行。你能提出任何关于同步互斥的逻辑或任何错误的建议吗?
    • 或任何更正。实际上,我正在尝试实现同步互斥机制。其中,当例程 1 正在执行 fmt.Println("value of z") 时,所有其他线程都被阻塞。对该实施有任何更正吗?
    • 我添加了一个简单的例子。我希望它更清楚。一旦一个互斥锁被锁定,其他 goroutine 就无法通过它,直到它被解锁。
    • 谢谢。但是,它会在此play.golang.org/p/Ojx6aOIAUR 中造成死锁。你能帮我解决这个问题吗?
    【解决方案3】:

    我认为,这是因为 runtime.LockOSThread(),runtime.UnlockOSThread 并非一直有效。它完全取决于CPU,执行环境等。它不能通过任何其他方式强制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多