2

私のコードには、3つの同時ルーチンがあります。私は自分のコードの概要を簡単に説明しようとしていますが、

Routine 1 {
do something

*Send int to Routine 2
Send int to Routine 3
Print Something
Print Something*

do something
}

Routine 2 {
do something

*Send int to Routine 1
Send int to Routine 3
Print Something
Print Something*

do something
}

Routine 3 {
do something

*Send int to Routine 1
Send int to Routine 2
Print Something
Print Something*

do something
}

main {
routine1
routine2
routine3
}

2つの間のコード(2つのスターマーク間のコード)が実行されている間、制御の流れが他のゴルーチンに移動してはならないことを望んでいます。たとえば、routine1が2つのスター間のイベント(イベントの送信と印刷)を実行している場合、ルーチン2と3をブロックする必要があります(実行のフローがルーチン1からルーチン2または3に渡されないことを意味します)。最後の印刷イベントを完了した後、実行のフローはルーチン2または3に渡される場合があります。誰かが指定することで私を助けてくれますか、どうすればこれを達成できますか?WaitGroupで上記の仕様を実装することは可能ですか?WaitGroupを使用して上記の例を実装する簡単な例を挙げて、誰かに教えてもらえますか。ありがとう。

注意:私は2つの送信オプションと2つの印刷オプションを提供しています。実際、送信と印刷はたくさんあります。

4

4 に答える 4

3

正しく理解できれば、各関数の一部と他の関数が同時に実行されないようにする必要があります。次のコードはこれを行いfmt.Printlnます。他のルーチンが実行されているため、行は発生しません。実行が印刷セクションに到達すると、他のルーチンが実行されている場合は終了するまで待機し、この印刷行が実行されている間、他のルーチンは開始および待機しません。それがあなたが探しているものであることを願っています。私がこれについて間違っているなら、私を訂正してください。

package main

import (
    "fmt"
    "rand"
    "sync"
)

var (
    mutex1, mutex2, mutex3 sync.Mutex
    wg sync.WaitGroup
)

func Routine1() {
    mutex1.Lock()
    // do something
    for i := 0; i < 200; i++ {
        mutex2.Lock()
        mutex3.Lock()
        fmt.Println("value of z")
        mutex2.Unlock()
        mutex3.Unlock()
    }
    // do something
    mutex1.Unlock()
    wg.Done()
}

func Routine2() {
    mutex2.Lock()
    // do something
    for i := 0; i < 200; i++ {
        mutex1.Lock()
        mutex3.Lock()
        fmt.Println("value of z")
        mutex1.Unlock()
        mutex3.Unlock()
    }
    // do something
    mutex2.Unlock()
    wg.Done()
}

func Routine3() {
    mutex3.Lock()
    // do something
    for i := 0; i < 200; i++ {
        mutex1.Lock()
        mutex2.Lock()
        fmt.Println("value of z")
        mutex1.Unlock()
        mutex2.Unlock()
    }
    // do something
    mutex3.Unlock()
    wg.Done()
}

func main() {
    wg.Add(3)
    go Routine1()
    go Routine2()
    Routine3()
    wg.Wait()
}

更新:ここでこれらの3つのミューテックスについて説明しましょう:ドキュメントにあるように、ミューテックスは「相互排他ロック」です。つまりLock、ミューテックスを呼び出すと、他の誰かが同じミューテックスをロックした場合、コードはそこで待機します。電話をかけた直後にUnlock、ブロックされたコードが再開されます。

ここでは、関数の最初でミューテックスをロックし、最後でロックを解除することで、各関数を独自のミューテックスに配置します。この単純なメカニズムにより、これらの関数と同時に必要なコードの一部を実行することを回避できます。たとえば、実行中に実行してはならないコードが必要な場合Routine1mutex1、そのコードの最初でロックし、最後でロックを解除するだけです。Routine2それは私がとの適切な行でしたことRoutine3です。それが物事を明確にすることを願っています。

于 2011-11-30T00:50:26.987 に答える
2

を使用できますsync.Mutex。たとえば、im.Lock()との間のすべてim.Unlock()が他のゴルーチンを除外します。

package main

import (
"fmt"
"sync"
)

func f1(wg *sync.WaitGroup, im *sync.Mutex, i *int) {
  for {
    im.Lock()
    (*i)++
    fmt.Printf("Go1: %d\n", *i)
    done := *i >= 10
    im.Unlock()
    if done {
      break
    }
  }
  wg.Done()
}

func f2(wg *sync.WaitGroup, im *sync.Mutex, i *int) {
  for {
    im.Lock()
    (*i)++
    fmt.Printf("Go2: %d\n", *i)
    done := *i >= 10
    im.Unlock()
    if done {
      break
    }
  }
  wg.Done()
}

func main() {
    var wg sync.WaitGroup

    var im sync.Mutex
    var i int

    wg.Add(2)
    go f1(&wg, &im, &i)
    go f2(&wg, &im, &i)
    wg.Wait()   

}
于 2011-11-29T21:06:29.060 に答える
0

別の方法は、一度に1つのゴルーチンのみを実行できる制御チャネルを用意し、各ルーチンがアトミック操作の実行を完了するたびに「制御ロック」に送り返すことです。

package main
import "fmt"
import "time"

func routine(id int, control chan struct{}){
    for {
        // Get the control
        <-control
        fmt.Printf("routine %d got control\n", id)
        fmt.Printf("A lot of things happen here...")
        time.Sleep(1)
        fmt.Printf("... but only in routine %d !\n", id)
        fmt.Printf("routine %d gives back control\n", id)
        // Sending back the control to whichever other routine catches it
        control<-struct{}{}
    }
}

func main() {
    // Control channel is blocking
    control := make(chan struct{})

    // Start all routines
    go routine(0, control)
    go routine(1, control)
    go routine(2, control)

    // Sending control to whichever catches it first
    control<-struct{}{}
    // Let routines play for some time...
    time.Sleep(10)
    // Getting control back and terminating
    <-control
    close(control)
    fmt.Println("Finished !")
}

これは印刷します:

routine 0 got control
A lot of things happen here...... but only in routine 0 !
routine 0 gives back control
routine 1 got control
A lot of things happen here...... but only in routine 1 !
routine 1 gives back control
routine 2 got control
A lot of things happen here...... but only in routine 2 !
routine 2 gives back control
routine 0 got control
A lot of things happen here...... but only in routine 0 !
routine 0 gives back control
routine 1 got control
A lot of things happen here...... but only in routine 1 !
routine 1 gives back control
routine 2 got control
A lot of things happen here...... but only in routine 2 !
routine 2 gives back control
routine 0 got control
A lot of things happen here...... but only in routine 0 !
routine 0 gives back control
routine 1 got control
A lot of things happen here...... but only in routine 1 !
routine 1 gives back control
routine 2 got control
A lot of things happen here...... but only in routine 2 !
routine 2 gives back control
routine 0 got control
A lot of things happen here...... but only in routine 0 !
routine 0 gives back control
routine 1 got control
A lot of things happen here...... but only in routine 1 !
routine 1 gives back control
routine 2 got control
A lot of things happen here...... but only in routine 2 !
routine 2 gives back control
Finished !
于 2013-08-14T09:06:24.613 に答える
-2

他のルーチンを明示的に停止するライブラリ関数を求めていますか?Goや他のほとんどの言語では不可能であることを明確にしてください。そして、同期、ミューテックスのケースはあなたのケースでは不可能です。

于 2011-11-29T18:52:25.327 に答える