English 中文(简体)
顺便提一下,如何使用双向锁,等待例行工作。
原标题:In go, how to use mutex to lock and wait with go routines

I have code that is something like this:

var lock sync.Mutex

func DoSomething() {
  lock.Lock()
  go func() {
    defer lock.Unlock()
    // Code here
  }()
}

func Wait() {
  lock.Lock()
  lock.Unlock()
}

我需要<代码>Wait(,因为有时是因为 在<条码>上,我必须打上<条码>。 Exit 。 因此,在这种情况下,我需要完成。

只要I m只打上DoSomething()”一度,它就会被罚款,但当然,如果它两次叫,则第二次等到去。

DoSomething() // returns immediately
DoSomething() // waits until the first one finishes to return

如果我把锁定在 go路里,那么Wait()就在 go路开始之前就被召去。

func DoSomething() {
  go func() {
    lock.Lock()
    defer lock.Unlock()
    // Code here
  }()
}

DoSomething()
Wait() // this finishes before the goroutine even starts

我在<代码>sync中尝试了其他几个事情,但发现有些事情行之有效。

我甚至试图从<代码>DoSomething中抽出航道,将其称作 DoSomething(),但我无法这样做。

问题回答

Disclaimer: I am still learning go. I am not 100% sure that this is the idiomatic way to go (pun intended).


这种解决办法的想法是:我们不是直接使用一种方法,而是:

  • start a go routine from the get-go, which waits on some signal on a channel
  • when we want to do something, we write to the channel
  • to possibly synchronize with the execution, we can pass another channel on the channel - the back communication channel

把它放在一起,我们就这样做了:

package main

import "fmt"

// This is the channel used by doSomething() to be notified when it
var doSomethingChannel = make(chan chan<- interface{})

// This is the channel we expose as interface to the outside so we can trigger "doSomething" to... do something
func DoSomethingChannel() chan<- chan<- interface{} {
    return doSomethingChannel
}

func doSomething() {
    for {
        back := <- doSomethingChannel
        // code goes here
        fmt.Println("[GOROUTINE] Executing")

        // if the back-channel is set, i.e. if the caller wants to be informed, write a signal on the back-channel
        if back != nil {
            back<- struct{}{}
        }
    }
}

func main() {
    go doSomething()
    for i := 0; i < 11; i += 1 {
        // if i is even, we want to wait, otherwise we do not want to wait
        var back chan interface{} = nil
        if i % 2 == 0 {
            back = make(chan interface{})
            fmt.Printf("[CALLER] Waiting for execution %d
", i)
        } else {
            fmt.Printf("[CALLER] Calling for execution %d, will not wait
", i)
        }
        // send the back-channel to the DoSomethingChannel, this will trigger doSomething()
        DoSomethingChannel() <- back
        if back != nil {
            // Wait if back-channel was used
            <-back
            fmt.Printf("[CALLER] %d has been done
", i)
        }
    }
}

https://go.dev/play/p/tQaf0oJiYV-"rel=“nofollow noreferer”>go.dev demo





相关问题
Asynchronous data loading in Entity-Framework?

Did anyone hear about asynchronous executing of an EF query? I want my items control to be filled right when the form loads and the user should be able to view the list while the rest of the items ...

Does PHP support asynchronous programming?

I m new to PHP. I am familiar with ASP.NET which support asynchronous programming. That is, if one request needs to do some I/O job. It is suggested to program the web page with BeginProcess/...

How to cancel an asynchronous call?

How to cancel an asynchronous call? The .NET APM doesn t seem to support this operation. I have the following loop in my code which spawns multiple threads on the ThreadPool. When I click a button on ...

What can cause select to block in Python?

Here s a snippet of code I m using in a loop: while True: print loop rlist, wlist, xlist = select.select(readers, [], [], TIMEOUT) print selected # do stuff At a certain point, ...

热门标签