2

我有两个并发的 go 例程,如下所示,

Routine 1{                                                  

routine procedure   

critical section{                                                     
}

routine procedure                        
} 

Routine 2{                                                  

routine procedure   

critical section{                                                     
}

routine procedure                       
} 

是否可以通过使用一些内置函数来实现临界区?

4

6 回答 6

3

你的问题:

我有 N 个并发的 go 例程(所有或多或少相同的目的)。每一个都有一个关键部分。在进入临界区之前,每个例程只是做一些消息发送工作。当它进入临界区时,我需要所有其他例程必须停止执行,直到它退出临界区。是否可以在 GO 中使用任何库函数?

您所问的问题(在一个 goroutine 处于临界区时强制停止所有其他 goroutine)在 Go 程序中并不常见。没有库函数可以停止所有其他 goroutine,因此您需要通过在程序中的 goroutine 之间设计适当的同步来停止它们。典型的场景是所有的 goroutines(可能)同时运行,除了那些被阻塞的 goroutines。

要控制对 Go 程序中共享资源的并发访问,您可以使用 Go 通道、"sync"包、管道或网络连接。

使用sync.Mutex,Go 代码可能看起来像这样(但请记住,只要有可能,Go 程序最好使用 Go 通道而不是互斥锁):

package main

import "sync"

var m sync.Mutex
var wg sync.WaitGroup

func routine1() {
    ... do something ...

    m.Lock()
    ... critical section (access the shared resource here) ...
    m.Unlock()

    ... do something ...
    wg.Done()
}

func routine2() {
    ... do something ...

    m.Lock()
    ... critical section (access the shared resource here) ...
    m.Unlock()

    ... do something ...
    wg.Done()
}

func main() {
    wg.Add(1); go routine1()
    wg.Add(1); go routine2()
    wg.Wait()
}
于 2011-11-28T12:15:02.930 回答
1

您可以尝试使用缓冲通道:

c := make(chan int, 2)

这将在实际发送之前缓冲发送的数据。

于 2011-11-27T16:11:06.147 回答
1

你的意思是这样的吗?

package main

import "fmt"

func ping(recv <-chan int, send chan<- int, end chan<- bool) {
    fmt.Println("ping")
    send <- 11
    send <- 12
    r1 := <-recv
    r2 := <-recv
    fmt.Println("ping", r1, r2)
    end <- true
}

func pong(recv <-chan int, send chan<- int, end chan<- bool) {
    fmt.Println("pong")
    r1 := <-recv
    r2 := <-recv
    send <- 21
    send <- 22
    fmt.Println("pong", r1, r2)
    end <- true
}

func main() {
    chEnd := make(chan bool)
    chPing := make(chan int, 2)
    chPong := make(chan int, 2)
    go ping(chPing, chPong, chEnd)
    go pong(chPong, chPing, chEnd)
    <-chEnd
    <-chEnd
    fmt.Println("end")
}

输出:

ping
pong
pong 11 12
ping 21 22
end
于 2011-11-27T16:50:54.907 回答
1

我不认为,去实现关键部分有任何库。我认为 Arpssss 正在要求一个图书馆。

于 2011-11-27T17:03:15.913 回答
1

几种方法是可能的。一个简单的方法是使用为完整“事件”键入的通道。

package main

type int2 struct {
        a, b int
}

func Routine1(tx, rx chan int2) {
        var x, y int
        // ...
        tx <- int2{x, y}
        // ...
        z := <- rx // Two rx values in z.a, z.b
        // ...
}

func Routine2(rx, tx chan int2) {
        var x, y int
        // ...
        z := <- rx // Two rx values in z.a, z.b
        // ...
        tx <- int2{x, y}
        // ...
}

func main() {
        // ...
        tx, rx := make(chan int2), make(chan int2)
        go Routine1(tx, rx)
        go Routine2(rx, tx)
        // ...
}
于 2011-11-27T17:19:57.987 回答
1

这是一个基于通道的等价于 Atom 的解决方案。在启动 goroutine 之前执行此操作:

doingFileModificationJobs := make(chan bool, 1)
doingFileModificationJobs <- false

然后在启动 goroutines 时将此通道作为参数传递。请注意,只有一个频道。所有 goroutine 都使用相同的通道。

这将使您可以像使用互斥锁一样使用此通道。替换你的伪代码,

critical section{

<-doingFileModicationJobs

然后将关键部分伪代码的匹配右大括号替换为,

doingFileModications <- false

这样读起来很好,并且比“互斥锁”或“关键部分”等一般术语更具描述性。

这会序列化您的文件修改作业,并确保一次只能有一个 goroutine 执行它们。我认为这是临界区的常见概念,但如果你真的需要其他 goroutine 停止,即使它们只是在做消息发送工作,那么,那是一个不同的问题。

于 2011-11-28T21:26:20.687 回答