Go编程语言互相并发执行

huangapple go评论93阅读模式
英文:

Go Programming Language Mutual Concurrent Execution

问题

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

例程1{
例程过程

临界区{
}

例程过程
}

例程2{
例程过程

临界区{
}

例程过程
}

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

英文:

I have two concurrent go routines like below,

Routine 1{                                                  

routine procedure   

critical section{                                                     
}

routine procedure                        
} 

Routine 2{                                                  

routine procedure   

critical section{                                                     
}

routine procedure                       
} 

Is it possible by using some go inbuilt functions to implement critical section ?

答案1

得分: 3

你正在询问的是如何在一个关键部分中强制停止所有其他goroutine,这在Go程序中并不常见。没有库函数可以停止所有其他goroutine,因此您需要通过在程序中的goroutine之间设计适当的同步来停止它们。典型的情况是所有goroutine都可以(可能)并发运行,除非某些goroutine以某种方式被阻塞。

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

使用"sync.Mutex",Go代码可能如下所示(但请记住,尽可能使用Go通道而不是互斥锁):

package main

import "sync"

var m sync.Mutex
var wg sync.WaitGroup

func routine1() {
    ... 做一些事情 ...

    m.Lock()
    ... 关键部分(在这里访问共享资源)...
    m.Unlock()

    ... 做一些事情 ...
    wg.Done()
}

func routine2() {
    ... 做一些事情 ...

    m.Lock()
    ... 关键部分(在这里访问共享资源)...
    m.Unlock()

    ... 做一些事情 ...
    wg.Done()
}

func main() {
    wg.Add(1); go routine1()
    wg.Add(1); go routine2()
    wg.Wait()
}
英文:

Your question:

> I have N concurrent go routines (all more or less same purpose). Each of those have a critical section. Before entering critical section, each routine just do some message sending job. When it enters critical section, I need all other routines must stop execution until it exits critical section. Is it possible by using any library function in GO?

What you are asking about (to force a stop on all other goroutines while one goroutine is in the critical section) is not typical in Go programs. There is no library function to stop all other goroutines, so you will need to stop them by designing proper synchronization among goroutines in your program. The typical scenario is for all goroutines to (potentially) run concurrently, except for those goroutines that are blocked somehow.

To control concurrent access to a shared resource in a Go program you can use Go channels, the <code>"sync"</code> package, pipes, or network connections.

Using <code>sync.Mutex</code>, the Go code may look like this (but please keep in mind that, whenever possible, Go programs should preferably use Go channels instead of mutexes):

package main

import &quot;sync&quot;

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()
}

答案2

得分: 1

你可以尝试使用带缓冲的通道:

c := make(chan int, 2)

这样可以在实际发送数据之前缓冲发送的数据。

英文:

You could try using a buffered channel:

c := make(chan int, 2)

This will buffer the data sent before actually sending it.

答案3

得分: 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
英文:

Do you mean something like this?

package main

import &quot;fmt&quot;

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

func pong(recv &lt;-chan int, send chan&lt;- int, end chan&lt;- bool) {
	fmt.Println(&quot;pong&quot;)
	r1 := &lt;-recv
	r2 := &lt;-recv
	send &lt;- 21
	send &lt;- 22
	fmt.Println(&quot;pong&quot;, r1, r2)
	end &lt;- 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)
	&lt;-chEnd
	&lt;-chEnd
	fmt.Println(&quot;end&quot;)
}

Output:

ping
pong
pong 11 12
ping 21 22
end

答案4

得分: 1

我不认为Go语言中有任何实现临界区的库。我认为Arpssss正在寻找一个库。

英文:

I don't think, there is any library in go to implement critical section. I think Arpssss is asking for a library.

答案5

得分: 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 // 两个 rx 值分别存储在 z.a 和 z.b 中
        // ...
}

func Routine2(rx, tx chan int2) {
        var x, y int
        // ...
        z := <- rx // 两个 rx 值分别存储在 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)
        // ...
}
英文:

Several approaches are possible. A simple one is to use channels typed for the full "event".

package main

type int2 struct {
        a, b int
}

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

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

func main() {
        // ...
        tx, rx := make(chan int2), make(chan int2)
        go Routine1(tx, rx)
        go Routine2(rx, tx)
        // ...
}

答案6

得分: 1

这是一个基于通道的与Atom解决方案等效的方法。在启动goroutine之前执行以下操作:

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

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

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

critical section{

用以下方式替换

<-doingFileModicationJobs

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

doingFileModications <- false

这样读起来更清晰,并且比“互斥锁”或“关键部分”等通用术语更具描述性。

这将使您的文件修改作业串行化,并确保一次只能有一个goroutine执行它们。我认为这是关键部分的常见概念,但如果您真的需要其他goroutine停止,即使它们只是执行消息发送作业,那么这是一个不同的问题。

英文:

Here's a channel based equivalent to Atom's solution. Do this before starting your goroutines:

doingFileModificationJobs := make(chan bool, 1)
doingFileModificationJobs &lt;- false

and then pass this channel as a parameter when you start goroutines. Note that there is just one channel. All goroutines use this same channel.

This will let you use this channel like a mutex. Replace your pseudocode,

critical section{

with

&lt;-doingFileModicationJobs

and then replace the matching closing brace of your critical section pseudocode with,

doingFileModications &lt;- false

It reads nicely that way and is more descriptive than general terms like "mutex" or "critical section."

This serializes your file modification jobs and ensures that only one goroutine at a time can be be doing them. I think this is the common concept of a critical section, but if you really need other goroutines to stop, even if they are just doing the message sending jobs, well, that's a different problem.

huangapple
  • 本文由 发表于 2011年11月27日 23:55:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/8286806.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定