# #multithreading #go #concurrency #mutex
Вопрос:
Предположим, у меня есть набор гороутинов
wg := sync.WaitGroup{}
wg.Add(5)
go somefunction("A", amp;wg) //1
go somefunction("B", amp;wg) //2
go somefunction("A", amp;wg) //3
go somefunction("A", amp;wg) //4
go somefunction("B", amp;wg) //5
wg.Wait()
Мне требуется, чтобы одновременно выполнялась только одна подпрограмма определенной строки («A» или «B» здесь). В любое время должна выполняться только одна из некоторых функций(«A», amp;wg). Например, //1 и //2 запускаются одновременно. После завершения //2 запускается //5. После завершения //1 запускается любой из //3 или //4.
Я думал о разработке мьютекса на основе ключей, чтобы решить эту проблему.
somefunction(key string){
Lock(key)
//piece of code
Unlock(key)
}
Кусочек кода будет заблокирован для конкретного ключа здесь.
Комментарии:
1. Вы можете сделать это с
map[string]*sync.Mutex
помощью А. Но вам нужно быть осторожным, так как карта небезопасна для одновременных операций записи и чтения. Таким образом, вашиLock(key)
Unlock(key)
методы и также должны быть закрыты другимsync.Mutex
, если вы ожидаете, что ключи изменятся во время работы.
Ответ №1:
Давайте somefunction
возьмем параметр мьютекса и передадим один и тот же экземпляр мьютекса для одного и того же ключа.
func somefunction(mux *sync.Mutex, wg *sync.WaitGroup) {
mux.Lock()
defer mux.Unlock()
...
}
wg := amp;sync.WaitGroup{}
wg.Add(5)
muxA := amp;sync.Mutex{}
muxB := amp;sync.Mutex{}
go somefunction(muxA, wg) //1
go somefunction(muxB, wg) //2
go somefunction(muxA, wg) //3
go somefunction(muxA, wg) //4
go somefunction(muxB, wg) //5
wg.Wait()
Если вы хотите продолжать использовать доступ на основе ключей, вы можете сохранить мьютексы на карте:
muxmap := map[string]*sync.Mutex{
"A": amp;sync.Mutex{},
"B": amp;sync.Mutex{},
}
go somefunction(muxmap["A"], wg)
Ответ №2:
Вероятно, можно реализовать специальную блокировку, такую как
type StringKeyLock struct {
locks map[string]*sync.Mutex
mapLock sync.Mutex // to make the map safe concurrently
}
func NewStringKeyLock() *StringKeyLock {
return amp;StringKeyLock{locks: make(map[string]*sync.Mutex)}
}
func (l *StringKeyLock) getLockBy(key string) *sync.Mutex {
l.mapLock.Lock()
defer l.mapLock.Unlock()
ret, found := l.locks[key]
if found {
return ret
}
ret = amp;sync.Mutex{}
l.locks[key] = ret
return ret
}
func (l *StringKeyLock) Lock(key string) {
l.getLockBy(key).Lock()
}
func (l *StringKeyLock) Unlock(key string) {
l.getLockBy(key).Unlock()
}
Затем, чтобы инициализировать «глобальный» StringKeyLock
var stringKeyLock = NewStringKeyLock()
Наконец, использовать его
func somefunction(key string){
stringKeyLock.Lock(key)
//piece of code
stringKeyLock.Unlock(key)
}