Go Язык программирования Взаимное параллельное выполнение - PullRequest
2 голосов
/ 27 ноября 2011

У меня есть две параллельные процедуры go, как показано ниже,

Routine 1{                                                  

routine procedure   

critical section{                                                     
}

routine procedure                        
} 

Routine 2{                                                  

routine procedure   

critical section{                                                     
}

routine procedure                       
} 

Возможно ли использовать некоторые встроенные функции для реализации критической секции?

Ответы [ 6 ]

3 голосов
/ 28 ноября 2011

Ваш вопрос:

У меня есть N одновременных подпрограмм go (все более или менее одинаковые цели). У каждого из них есть критический раздел. Перед входом в критическую секцию каждая подпрограмма просто выполняет определенную работу по отправке сообщений. Когда он входит в критическую секцию, мне нужно, чтобы все остальные подпрограммы должны были остановить выполнение, пока он не выйдет из критической секции. Возможно ли это с помощью какой-либо библиотечной функции в GO?

То, о чем вы спрашиваете (принудительно остановить все другие программы, пока одна программа находится в критическом разделе), не является типичным для программ Go. Нет библиотечной функции для остановки всех других подпрограмм, поэтому вам нужно будет остановить их, разработав правильную синхронизацию между подпрограммами в вашей программе. Типичным сценарием является одновременное выполнение (потенциально) всех подпрограмм, за исключением тех подпрограмм, которые каким-либо образом заблокированы.

Для управления одновременным доступом к общему ресурсу в программе 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()
}
1 голос
/ 29 ноября 2011

Вот канал, основанный на решении Atom. Сделайте это перед тем, как начинать свои программы:

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

, а затем передать этот канал в качестве параметра при запуске процедур. Обратите внимание, что есть только один канал. Все программы используют один и тот же канал.

Это позволит вам использовать этот канал как мьютекс. Замените свой псевдокод,

critical section{

с

<-doingFileModicationJobs

и затем замените соответствующую закрывающую скобку псевдокода критической секции на

doingFileModications <- false

Это хорошо читается таким образом и является более описательным, чем общие термины, такие как «мьютекс» или «критическая секция».

Это сериализует ваши задания по модификации файлов и гарантирует, что их может выполнять только одна процедура за один раз. Я думаю, что это общая концепция критического раздела, но если вам действительно нужны другие программы для остановки, даже если они просто выполняют задания по отправке сообщений, это другая проблема.

1 голос
/ 27 ноября 2011

Возможны несколько подходов. Проще всего использовать каналы, набранные для полного «события».

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)
        // ...
}
1 голос
/ 27 ноября 2011

Я не думаю, что есть какая-либо библиотека для реализации критической секции. Я думаю, что Arpssss просит библиотеку.

1 голос
/ 27 ноября 2011

Вы имеете в виду что-то подобное?

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
1 голос
/ 27 ноября 2011

Вы можете попробовать использовать буферизованный канал:

c := make(chan int, 2)

Это буферизует данные, отправленные перед фактической отправкой.

...